Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate RZIL operations #69

Merged
merged 15 commits into from
Mar 22, 2024
Merged
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ rz_hexagon.egg-info/
Hexagon.json
.config
.last_llvm_commit_info
venv/
.venv
/rizin/
.venv/
.vscode
rizin/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "rzil_compiler"]
path = rzil_compiler
url = [email protected]:rizinorg/rz-rzilcompiler.git
8 changes: 8 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Files: .gitignore
Copyright: 2021 RizinOrg <[email protected]>
License: LGPL-3.0-only

Files: .gitmodules
Copyright: 2022 Rot127 <[email protected]>
License: LGPL-3.0-only

Files: .pylintrc
Copyright: 2021 RizinOrg <[email protected]>
License: LGPL-3.0-only
Expand Down Expand Up @@ -54,3 +58,7 @@ License: LGPL-3.0-only
Files: import/*
Copyright: 2022 Rot127 <[email protected]>
License: LGPL-3.0-only

Files: handwritten/*.json
Copyright: 2023 Rot127 <[email protected]>
License: LGPL-3.0-only
75 changes: 75 additions & 0 deletions Conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# SPDX-FileCopyrightText: 2022 Rot127 <[email protected]>
# SPDX-License-Identifier: LGPL-3.0-only

import subprocess

from enum import StrEnum
from pathlib import Path

from helperFunctions import log


class OutputFile(StrEnum):
"""
Enum of paths used by the components.

<REPO> is replaced with the path to the repositories root.
<ARCH> is replaced with the architecture name.
"""

OUT_BASE = "<REPO>/rizin/"
LIBRZ_DIR = "<REPO>/rizin/librz/"
IL_OPS_DIR = "<REPO>/rizin/librz/arch/isa/hexagon/il_ops/"

ANA_TESTS = "<REPO>/rizin/test/db/analysis/hexagon"
ASM_TESTS = "<REPO>/rizin/test/db/asm/hexagon"
RZIL_TESTS = "<REPO>/rizin/test/db/rzil/hexagon"
ANALYSIS_HEXAGON_C = "<REPO>/rizin/librz/arch/p/analysis/analysis_hexagon.c"
ASM_HEXAGON_C = "<REPO>/rizin/librz/arch/p/asm/asm_hexagon.c"
CC_HEXAGON_32_SDB_TXT = "<REPO>/rizin/librz/arch/types/cc-hexagon-32.sdb.txt"
HEXAGON_IL_C = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_il.c"
HEXAGON_IL_GETTER_TABLE_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_il_getter_table.h"
HEXAGON_IL_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_il.h"
HEXAGON_ARCH_C = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_arch.c"
HEXAGON_ARCH_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_arch.h"
HEXAGON_C = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon.c"
HEXAGON_DISAS_C = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_disas.c"
HEXAGON_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon.h"
HEXAGON_INSN_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_insn.h"
HEXAGON_REG_TABLES_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_reg_tables.h"
HEXAGON_DWARF_REG_TABLE_H = "<REPO>/rizin/librz/arch/isa/hexagon/hexagon_dwarf_reg_num_table.inc"


class Conf:
"""
Holds all the configurable values like paths.
"""

@staticmethod
def replace_placeholders(path_str: str) -> str:
if "<REPO>" in path_str:
root = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
check=True,
stdout=subprocess.PIPE,
)
root_dir = Path(root.stdout.decode("utf8").strip("\n"))
if not root_dir.exists():
raise NotADirectoryError(str(root_dir))

path_str = path_str.replace("<REPO>", str(root_dir))
return path_str

@staticmethod
def get_path(file: OutputFile) -> Path:
return Path(Conf.replace_placeholders(file))

@staticmethod
def check_path(path: Path, is_file: bool = True) -> None:
"""Checks a given path and creates the directory if it doesn't exist."""
if not path.exists():
target = path
if is_file:
target = path.parent
log(f"Create dir {str(target)}")
target.mkdir(parents=True, exist_ok=True)
4 changes: 4 additions & 0 deletions HardwareRegister.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ def set_well_defined_asm_names(self, llvm_asm: str, llvm_alt: list):
match_alias = re.search(r"^[rcpgvqs]\d{1,2}(:\d{1,2})?$", ",".join(llvm_alt))
if (llvm_asm == "p3:0") or (llvm_asm in llvm_alt):
match_asm = None
if (llvm_asm in llvm_alt) and len(llvm_alt) == 1:
# Alias of some regs equal asm name.
self.asm_name = llvm_asm
self.alias = []
if match_asm and match_alias:
raise ImplementationException(
"HW reg alias and asm names match same pattern: alias: {} asm: {}".format(",".join(llvm_alt), llvm_asm)
Expand Down
18 changes: 13 additions & 5 deletions Immediate.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ def __init__(
self.encoding_width = 0 # Num. bits stored in encoding.
self.total_width = 0

self.parse_imm_type(llvm_type)

def parse_imm_type(self, llvm_imm_type: str) -> None:
"""Parse immediate types like: u4_2Imm. This method sets all kinds of flags, the scale and total width."""
self.parse_imm_type(llvm_type, llvm_syntax == "II")

def parse_imm_type(self, llvm_imm_type: str, is_second: bool) -> None:
"""Parse immediate types like: u4_2Imm. This method sets
all kinds of flags, the scale, total width and ISA identifier.
Args:
llvm_imm_type: The llvm type string (e.g.: u4_2Imm).
is_second: Flag if this immediate is the second immediate in the instruction.
"""
type_letter = re.search(r"^([a-z]+)\d{1,2}", llvm_imm_type)
if not type_letter:
raise ImplementationException("Unhandled immediate type: {}".format(llvm_imm_type))
Expand All @@ -80,6 +85,7 @@ def parse_imm_type(self, llvm_imm_type: str) -> None:
elif type_letter == "a" or type_letter == "b":
self.is_signed = True
self.is_pc_relative = True
type_letter = "r" # In QEMUs shortcode all PC relative immediates are named with 'r'
# Constant value -1
elif type_letter == "n":
self.is_signed = True
Expand All @@ -95,6 +101,7 @@ def parse_imm_type(self, llvm_imm_type: str) -> None:
return
else:
raise ImplementationException("Unhandled immediate type: {}".format(llvm_imm_type))
self.isa_id = type_letter.upper() if is_second else type_letter

# Value before _ represents number of encoded bits.
result = re.search(r"[a-z](\d+)\_", llvm_imm_type)
Expand Down Expand Up @@ -147,7 +154,8 @@ def c_template(self, force_extendable=False) -> str:
if self.total_width == 32:
info.append("HEX_OP_TEMPLATE_FLAG_IMM_DOUBLE_HASH")
info = " | ".join(info)
r = f".info = {info}, .masks = {{ {self.opcode_mask.c_template} }}"
r = f".info = {info}, .masks = {{ {self.opcode_mask.c_template} }}, "
r += f".isa_id = '{self.isa_id if self.isa_id != '' else 0}'"
if self.scale > 0:
r += f", .imm_scale = {self.scale}"
return r
9 changes: 7 additions & 2 deletions InstructionTemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import HexagonArchInfo
import PluginInfo
from rzilcompiler.Compiler import RZILInstruction
from Immediate import Immediate
from ImplementationException import ImplementationException
from InstructionEncoding import InstructionEncoding
Expand Down Expand Up @@ -87,7 +88,7 @@ def __init__(self, llvm_instruction):
self.llvm_new_operand_index: bool = None
self.is_predicated: bool = False
self.is_pred_new: bool = False
self.is_pred_false: bool = False # Duplex can have both, true and false predicates.
self.is_pred_false: bool = False
self.is_pred_true: bool = False

# Special
Expand All @@ -97,6 +98,8 @@ def __init__(self, llvm_instruction):
self.is_loop_begin: bool = None
self.loop_member = None

self.il_ops: RZILInstruction = None

# Execution specific (Interesting for decompiler plugin)
# The address mode of load/store instructions
self.addr_mode = None
Expand Down Expand Up @@ -216,6 +219,8 @@ def parse_instruction(self) -> None:
# Indices of new values (stored in "opNewValue") are only for non predicates.
is_new_value = self.new_operand_index == index and self.has_new_non_predicate
operand = Register(op_name, op_type, is_new_value, index)
# Second letter in reg name is used in QEMU shortcode to identify the register.
operand.isa_id = op_name[1]
# Whether the predicate registers holds a new value is denoted in "isPredicatedNew".
if self.is_pred_new and operand.is_predicate:
operand.is_new_value = True
Expand Down Expand Up @@ -314,7 +319,7 @@ def get_template_in_c(self) -> str:
flags.append("HEX_INSN_TEMPLATE_FLAG_LOOP_0")
elif self.loop_member == LoopMembership.HEX_LOOP_1:
flags.append("HEX_INSN_TEMPLATE_FLAG_LOOP_1")
if flags != []:
if flags:
flags = " | ".join(flags)
code += f".flags = {flags},\n"
code += "}"
Expand Down
Loading
Loading