diff options
| author | Peter LaFosse <peter@vector35.com> | 2021-07-29 13:08:03 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2021-09-05 10:09:10 -0400 |
| commit | a24b82f9b3d5dbb76f700664a97f3d4904acce30 (patch) | |
| tree | 981e990b9479e0318b4e7d8fb25038ed43fc8d18 | |
| parent | 764063b2b44dbeba5f2f318c971e4f4acfb48427 (diff) | |
Remove some unnecessary properties for various derived HLIL Instructions, add HLIL vars_read/vars_written
Additional progress on HLILInstruction refactor
| -rw-r--r-- | python/architecture.py | 11 | ||||
| -rw-r--r-- | python/binaryview.py | 5 | ||||
| -rw-r--r-- | python/highlevelil.py | 1008 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 1 | ||||
| -rw-r--r-- | python/types.py | 1708 | ||||
| -rw-r--r-- | python/variable.py | 4 | ||||
| -rw-r--r-- | suite/testcommon.py | 26 |
7 files changed, 1586 insertions, 1177 deletions
diff --git a/python/architecture.py b/python/architecture.py index fdec7fbf..f77778bc 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -483,17 +483,6 @@ class Architecture(metaclass=_ArchitectureMetaClass): def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) - # def __setattr__(self, name, value): - # if ((name == "name") or (name == "endianness") or (name == "address_size") or - # (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length") or - # (name == "get_instruction_alignment")): - # raise AttributeError("attribute '%s' is read only" % name) - # else: - # try: - # object.__setattr__(self, name, value) - # except AttributeError: - # raise AttributeError("attribute '%s' is read only" % name) - @classmethod def register(cls) -> None: binaryninja._init_plugins() diff --git a/python/binaryview.py b/python/binaryview.py index 33983045..449d38cb 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -5615,7 +5615,7 @@ class BinaryView: raise ValueError(error_str) return variable.PossibleValueSet(self.arch, result) - def get_type_by_name(self, name): + def get_type_by_name(self, name:'types.QualifiedName') -> Optional['types.Type']: """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` @@ -7587,6 +7587,9 @@ class DataVariable: # elif t.type_class == TypeClass.WideCharTypeClass: + @value.setter + def value(self, value:bytes) -> None: + self.view.write(self.address, value) @property def type(self) -> '_types.Type': diff --git a/python/highlevelil.py b/python/highlevelil.py index 2aadee13..176b97b3 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -22,6 +22,7 @@ import ctypes import struct from typing import Optional, Generator, List, Union, Any, NewType, Tuple from dataclasses import dataclass +from enum import Enum # Binary Ninja components from . import _binaryninjacore as core @@ -51,11 +52,17 @@ HighLevelILOperandType = Union[ List[int], List[variable.Variable], List['mediumlevelil.SSAVariable'], + List['HighLevelILInstruction'], Optional[int], float, 'GotoLabel' ] +VariablesList = List[Union['mediumlevelil.SSAVariable', variable.Variable]] +class VariableReferenceType(Enum): + Read = 0 + Written = 1 + AddressTaken = 2 @dataclass(frozen=True) class HighLevelILOperationAndSize: @@ -126,7 +133,6 @@ class HighLevelILInstruction: core_instr:CoreHighLevelILInstruction as_ast:bool instr_index:InstructionIndex - operand_names = tuple() @classmethod def create(cls, func:'HighLevelILFunction', expr_index:ExpressionIndex, as_ast:bool=True, instr_index:Optional[InstructionIndex]=None) -> 'HighLevelILInstruction': @@ -275,26 +281,24 @@ class HighLevelILInstruction: return self.core_instr.operands @property - def vars_written(self) -> List[Union[variable.Variable, 'mediumlevelil.SSAVariable']]: + def vars_written(self) -> VariablesList: """List of variables written by instruction""" return [] @property - def operands(self) -> Generator[HighLevelILOperandType, None, None]: - for operand_name in self.operand_names: - assert hasattr(self, operand_name), f"No operand '{operand_name}' for instruction {repr(self)}({self.operation})" - yield self.__getattribute__(operand_name) + def vars_read(self) -> VariablesList: + """List of variables read by instruction""" + return [] + + @property + def vars_address_taken(self) -> VariablesList: + """List of variables whose address is taken by instruction""" + return [] @property - def vars_read(self) -> List[Union[variable.Variable, 'mediumlevelil.SSAVariable']]: + def vars_referenced(self) -> VariablesList: """List of variables read by instruction""" - result = [] - for operand in self.operands: - if (isinstance(operand, variable.Variable)) or (isinstance(operand, mediumlevelil.SSAVariable)): - result.append(operand) - elif isinstance(operand, HighLevelILInstruction): - result += operand.vars_read - return result + return [] @property def parent(self) -> Optional['HighLevelILInstruction']: @@ -533,27 +537,32 @@ class Call(ControlFlow): return NotImplemented @property - def vars_read(self) -> List[Union['mediumlevelil.SSAVariable', variable.Variable]]: - result = [] - for param in self.params: - if isinstance(param, HighLevelILInstruction): - result.extend(param.vars_read) - else: - assert False, "Call.params returned object other than Variable, SSAVariable or MediumLevelILInstruction" - return result + def vars_referenced(self) -> VariablesList: + return [v for i in self.params for v in i.vars_referenced] + @dataclass(frozen=True, repr=False) class UnaryOperation(HighLevelILInstruction): - operand_names = tuple(["src"]) @property def src(self) -> HighLevelILInstruction: return self.get_expr(0) + @property + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def vars_read(self) -> VariablesList: + return self.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src] + @dataclass(frozen=True, repr=False) class BinaryOperation(HighLevelILInstruction): - operand_names = tuple(["left", "right"]) @property def left(self) -> HighLevelILInstruction: @@ -563,10 +572,21 @@ class BinaryOperation(HighLevelILInstruction): def right(self) -> HighLevelILInstruction: return self.get_expr(1) + @property + def vars_referenced(self) -> VariablesList: + return [*self.left.vars_referenced, *self.right.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.left, self.right] + @dataclass(frozen=True, repr=False) class Carry(Arithmetic): - operand_names = tuple(["left", "right", "carry"]) @property def left(self) -> HighLevelILInstruction: @@ -580,6 +600,17 @@ class Carry(Arithmetic): def carry(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*self.left.vars_referenced, *self.right.vars_referenced, *self.carry.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.left, self.right, self.carry] @dataclass(frozen=True, repr=False) class Comparison(BinaryOperation): @@ -638,12 +669,11 @@ class Tailcall(Call): @dataclass(frozen=True, repr=False) class HighLevelILNop(HighLevelILInstruction): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) class HighLevelILBlock(HighLevelILInstruction): - operand_names = tuple(["body"]) @property def body(self) -> List[HighLevelILInstruction]: @@ -653,10 +683,17 @@ class HighLevelILBlock(HighLevelILInstruction): for expr in self.body: yield expr + @property + def vars_referenced(self) -> VariablesList: + return [v for i in self for v in i.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.body] + @dataclass(frozen=True, repr=False) class HighLevelILIf(ControlFlow): - operand_names = tuple(["condition", "true", "false"]) @property def condition(self) -> HighLevelILInstruction: @@ -670,10 +707,17 @@ class HighLevelILIf(ControlFlow): def false(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.true.vars_referenced, *self.false.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.condition, self.true, self.false] + @dataclass(frozen=True, repr=False) class HighLevelILWhile(Loop): - operand_names = tuple(["condition", "body"]) @property def condition(self) -> HighLevelILInstruction: @@ -683,10 +727,17 @@ class HighLevelILWhile(Loop): def body(self) -> HighLevelILInstruction: return self.get_expr(1) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.body.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.condition, self.body] + @dataclass(frozen=True, repr=False) class HighLevelILWhile_ssa(Loop, SSA): - operand_names = tuple(["condition_phi", "condition", "body"]) @property def condition_phi(self) -> HighLevelILInstruction: @@ -700,10 +751,17 @@ class HighLevelILWhile_ssa(Loop, SSA): def body(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition_phi.vars_referenced, *self.condition.vars_referenced, *self.body.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.condition_phi, self.condition, self.body] + @dataclass(frozen=True, repr=False) class HighLevelILDo_while(Loop): - operand_names = tuple(["body", "condition"]) @property def body(self) -> HighLevelILInstruction: @@ -713,10 +771,17 @@ class HighLevelILDo_while(Loop): def condition(self) -> HighLevelILInstruction: return self.get_expr(1) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.body.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.body, self.condition] + @dataclass(frozen=True, repr=False) class HighLevelILDo_while_ssa(Loop, SSA): - operand_names = tuple(["body", "condition_phi", "condition"]) @property def body(self) -> HighLevelILInstruction: @@ -730,10 +795,20 @@ class HighLevelILDo_while_ssa(Loop, SSA): def condition(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition_phi.vars_referenced, *self.condition.vars_referenced, *self.body.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.condition.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.init, self.condition_phi, self.condition, self.body] @dataclass(frozen=True, repr=False) class HighLevelILFor(Loop): - operand_names = tuple(["init", "condition", "update", "body"]) @property def init(self) -> HighLevelILInstruction: @@ -751,10 +826,25 @@ class HighLevelILFor(Loop): def body(self) -> HighLevelILInstruction: return self.get_expr(3) + @property + def vars_referenced(self) -> VariablesList: + return [*self.init.vars_referenced, *self.condition.vars_referenced, *self.update.vars_referenced, *self.body.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.update.vars_read, *self.init.vars_read, *self.body.vars_read] + + @property + def vars_written(self) -> VariablesList: + return [*self.update.vars_written, *self.init.vars_written] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.init, self.condition, self.update, self.body] + @dataclass(frozen=True, repr=False) class HighLevelILFor_ssa(Loop, SSA): - operand_names = tuple(["init", "condition_phi", "condition", "update"]) @property def init(self) -> HighLevelILInstruction: @@ -776,10 +866,25 @@ class HighLevelILFor_ssa(Loop, SSA): def body(self) -> HighLevelILInstruction: return self.get_expr(3) + @property + def vars_referenced(self) -> VariablesList: + return [*self.init.vars_referenced, *self.condition_phi.vars_referenced, *self.condition.vars_referenced, *self.update.vars_referenced, *self.body.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.update.vars_read, *self.init.vars_read, *self.body.vars_read] + + @property + def vars_written(self) -> VariablesList: + return [*self.update.vars_written, *self.init.vars_written] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.init, self.condition_phi, self.condition, self.update, self.body] + @dataclass(frozen=True, repr=False) class HighLevelILSwitch(ControlFlow): - operand_names = tuple(["condition", "default", "cases"]) @property def condition(self) -> HighLevelILInstruction: @@ -793,10 +898,21 @@ class HighLevelILSwitch(ControlFlow): def cases(self) -> List[HighLevelILInstruction]: return self.get_expr_list(2, 3) + @property + def vars_referenced(self) -> VariablesList: + return [*self.condition.vars_referenced, *self.default.vars_referenced, *[v for i in self.cases for v in i.vars_referenced]] + + @property + def vars_read(self) -> VariablesList: + return [*self.condition.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.condition, self.default, self.cases] + @dataclass(frozen=True, repr=False) class HighLevelILCase(HighLevelILInstruction): - operand_names = tuple(["values", "body"]) @property def values(self) -> List[HighLevelILInstruction]: @@ -806,70 +922,102 @@ class HighLevelILCase(HighLevelILInstruction): def body(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*[v for i in self.values for v in i.vars_referenced], *self.body.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.values, self.body] + @dataclass(frozen=True, repr=False) class HighLevelILBreak(Terminal): - operand_names = tuple() - + pass @dataclass(frozen=True, repr=False) class HighLevelILContinue(ControlFlow): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) class HighLevelILJump(Terminal): - operand_names = tuple(["dest"]) @property def dest(self) -> HighLevelILInstruction: return self.get_expr(0) + @property + def vars_referenced(self) -> VariablesList: + return self.dest.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest] + @dataclass(frozen=True, repr=False) class HighLevelILRet(ControlFlow): - operand_names = tuple(["src"]) @property def src(self) -> List[HighLevelILInstruction]: return self.get_expr_list(0, 1) + @property + def vars_referenced(self) -> VariablesList: + return [v for i in self.src for v in i.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src] + @dataclass(frozen=True, repr=False) class HighLevelILNoret(Terminal): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) class HighLevelILGoto(Terminal): - operand_names = tuple(["target"]) @property def target(self) -> GotoLabel: return self.get_label(0) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.target] + @dataclass(frozen=True, repr=False) class HighLevelILLabel(HighLevelILInstruction): - operand_names = tuple(["target"]) @property def target(self) -> GotoLabel: return self.get_label(0) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.target] + @dataclass(frozen=True, repr=False) class HighLevelILVar_declare(HighLevelILInstruction): - operand_names = tuple(["var"]) @property def var(self) -> variable.Variable: return self.get_var(0) + @property + def vars_referenced(self) -> VariablesList: + return [self.var] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.var] @dataclass(frozen=True, repr=False) class HighLevelILVar_init(HighLevelILInstruction): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> variable.Variable: @@ -879,10 +1027,25 @@ class HighLevelILVar_init(HighLevelILInstruction): def src(self) -> HighLevelILInstruction: return self.get_expr(1) + @property + def vars_referenced(self) -> VariablesList: + return [self.dest, *self.src.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.src.vars_referenced + + @property + def vars_written(self) -> VariablesList: + return [self.dest] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILVar_init_ssa(SSA): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> 'mediumlevelil.SSAVariable': @@ -892,10 +1055,25 @@ class HighLevelILVar_init_ssa(SSA): def src(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [self.dest, *self.src.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.src.vars_referenced + + @property + def vars_written(self) -> VariablesList: + return [self.dest] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILAssign(HighLevelILInstruction): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> HighLevelILInstruction: @@ -905,10 +1083,25 @@ class HighLevelILAssign(HighLevelILInstruction): def src(self) -> HighLevelILInstruction: return self.get_expr(1) + # @property + # def vars_written(self) -> VariablesList: + # return self.dest.vars_referenced + + # @property + # def vars_read(self) -> VariablesList: + # return self.src.vars_referenced + + @property + def vars_referenced(self) -> VariablesList: + return [*self.src.vars_referenced, *self.dest.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILAssign_unpack(HighLevelILInstruction): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> List[HighLevelILInstruction]: @@ -918,10 +1111,25 @@ class HighLevelILAssign_unpack(HighLevelILInstruction): def src(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_written(self) -> VariablesList: + return [j for i in self.dest for j in i.vars_written] + + # @property + # def vars_read(self) -> VariablesList: + # return self.src.vars_referenced + + @property + def vars_referenced(self) -> VariablesList: + return [*self.vars_read, *self.vars_written] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILAssign_mem_ssa(SSA): - operand_names = tuple(["dest", "dest_memory", "src", "src_memory"]) @property def dest(self) -> HighLevelILInstruction: @@ -939,10 +1147,13 @@ class HighLevelILAssign_mem_ssa(SSA): def src_memory(self) -> int: return self.get_int(3) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.dest_memory, self.src, self.src_memory] + @dataclass(frozen=True, repr=False) class HighLevelILAssign_unpack_mem_ssa(SSA): - operand_names = tuple(["dest", "dest_memory", "src", "src_memory"]) @property def dest(self) -> List[HighLevelILInstruction]: @@ -960,28 +1171,51 @@ class HighLevelILAssign_unpack_mem_ssa(SSA): def src_memory(self) -> int: return self.get_int(4) + @property + def vars_written(self) -> VariablesList: + return [v for i in self.dest for v in i.vars_referenced] + + @property + def vars_read(self) -> VariablesList: + return self.src.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.dest_memory, self.src, self.src_memory] + @dataclass(frozen=True, repr=False) class HighLevelILVar(HighLevelILInstruction): - operand_names = tuple(["var"]) @property def var(self) -> variable.Variable: return self.get_var(0) + @property + def vars_referenced(self) -> VariablesList: + return [self.var] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.var] @dataclass(frozen=True, repr=False) class HighLevelILVar_ssa(SSA): - operand_names = tuple(["var"]) @property def var(self) -> 'mediumlevelil.SSAVariable': return self.get_var_ssa(0, 1) + @property + def vars_referenced(self) -> VariablesList: + return [self.var] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.var] @dataclass(frozen=True, repr=False) class HighLevelILVar_phi(SSA): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> 'mediumlevelil.SSAVariable': @@ -991,10 +1225,25 @@ class HighLevelILVar_phi(SSA): def src(self) -> List['mediumlevelil.SSAVariable']: return self.get_var_ssa_list(2, 3) + @property + def vars_written(self) -> VariablesList: + return [self.dest] + + @property + def vars_read(self) -> VariablesList: + return self.src # type: ignore + + @property + def vars_referenced(self) -> VariablesList: + return [self.dest, *self.src] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILMem_phi(Memory): - operand_names = tuple(["dest", "src"]) @property def dest(self) -> int: @@ -1004,10 +1253,13 @@ class HighLevelILMem_phi(Memory): def src(self) -> List[int]: return self.get_int_list(1) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.src] + @dataclass(frozen=True, repr=False) class HighLevelILStruct_field(HighLevelILInstruction): - operand_names = tuple(["src", "offset", "member_index"]) @property def src(self) -> HighLevelILInstruction: @@ -1021,10 +1273,17 @@ class HighLevelILStruct_field(HighLevelILInstruction): def member_index(self) -> Optional[int]: return self.get_member_index(2) + @property + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.offset, self.member_index] + @dataclass(frozen=True, repr=False) class HighLevelILArray_index(HighLevelILInstruction): - operand_names = tuple(["src", "index"]) @property def src(self) -> HighLevelILInstruction: @@ -1034,10 +1293,17 @@ class HighLevelILArray_index(HighLevelILInstruction): def index(self) -> HighLevelILInstruction: return self.get_expr(1) + @property + def vars_referenced(self) -> VariablesList: + return [*self.src.vars_referenced, *self.index.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.index] + @dataclass(frozen=True, repr=False) class HighLevelILArray_index_ssa(SSA): - operand_names = tuple(["src", "src_memory", "index"]) @property def src(self) -> HighLevelILInstruction: @@ -1051,10 +1317,17 @@ class HighLevelILArray_index_ssa(SSA): def index(self) -> HighLevelILInstruction: return self.get_expr(2) + @property + def vars_referenced(self) -> VariablesList: + return [*self.src.vars_referenced, *self.index.vars_referenced] + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.src_memory, self.index] + @dataclass(frozen=True, repr=False) class HighLevelILSplit(HighLevelILInstruction): - operand_names = tuple(["high", "low"]) @property def high(self) -> HighLevelILInstruction: @@ -1064,19 +1337,22 @@ class HighLevelILSplit(HighLevelILInstruction): def low(self) -> HighLevelILInstruction: return self.get_expr(1) - -@dataclass(frozen=True, repr=False) -class HighLevelILDeref(HighLevelILInstruction): - operand_names = tuple(["src"]) + @property + def vars_referenced(self) -> VariablesList: + return [*self.high.vars_referenced, *self.low.vars_referenced] @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + def operands(self) -> List[HighLevelILOperandType]: + return [self.high, self.low] + + +@dataclass(frozen=True, repr=False) +class HighLevelILDeref(UnaryOperation): + pass @dataclass(frozen=True, repr=False) class HighLevelILDeref_field(HighLevelILInstruction): - operand_names = tuple(["src", "offset", "member_index"]) @property def src(self) -> HighLevelILInstruction: @@ -1090,10 +1366,17 @@ class HighLevelILDeref_field(HighLevelILInstruction): def member_index(self) -> Optional[int]: return self.get_member_index(2) + @property + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.offset, self.member_index] + @dataclass(frozen=True, repr=False) class HighLevelILDeref_ssa(SSA): - operand_names = tuple(["src", "src_memory"]) @property def src(self) -> HighLevelILInstruction: @@ -1103,10 +1386,17 @@ class HighLevelILDeref_ssa(SSA): def src_memory(self) -> int: return self.get_int(1) + @property + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.src_memory] + @dataclass(frozen=True, repr=False) class HighLevelILDeref_field_ssa(SSA): - operand_names = tuple(["src", "src_memory", "offset", "member_index"]) @property def src(self) -> HighLevelILInstruction: @@ -1124,37 +1414,57 @@ class HighLevelILDeref_field_ssa(SSA): def member_index(self) -> Optional[int]: return self.get_member_index(3) + @property + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.src, self.src_memory, self.offset, self.member_index] + @dataclass(frozen=True, repr=False) -class HighLevelILAddress_of(HighLevelILInstruction): - operand_names = tuple(["src"]) +class HighLevelILAddress_of(UnaryOperation): @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + def vars_referenced(self) -> VariablesList: + return self.src.vars_referenced + + @property + def vars_read(self) -> VariablesList: + return [] + + @property + def vars_address_taken(self) -> VariablesList: + return self.src.vars_referenced @dataclass(frozen=True, repr=False) class HighLevelILConst(Constant): - operand_names = tuple(["constant"]) @property def constant(self) -> int: return self.get_int(0) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.constant] + @dataclass(frozen=True, repr=False) class HighLevelILConst_ptr(Constant): - operand_names = tuple(["constant"]) @property def constant(self) -> int: return self.get_int(0) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.constant] + @dataclass(frozen=True, repr=False) class HighLevelILExtern_ptr(Constant): - operand_names = tuple(["constant", "offset"]) @property def constant(self) -> int: @@ -1164,24 +1474,31 @@ class HighLevelILExtern_ptr(Constant): def offset(self) -> int: return self.get_int(1) + def operands(self) -> List[HighLevelILOperandType]: + return [self.constant, self.offset] + @dataclass(frozen=True, repr=False) class HighLevelILFloat_const(Constant): - operand_names = tuple(["constant"]) @property def constant(self) -> float: return self.get_float(0) + def operands(self) -> List[HighLevelILOperandType]: + return [self.constant] + @dataclass(frozen=True, repr=False) class HighLevelILImport(Constant): - operand_names = tuple(["constant"]) @property def constant(self) -> int: return self.get_int(0) + def operands(self) -> List[HighLevelILOperandType]: + return [self.constant] + @dataclass(frozen=True, repr=False) class HighLevelILAdd(Arithmetic, BinaryOperation): @@ -1239,20 +1556,8 @@ class HighLevelILRol(Arithmetic, BinaryOperation): @dataclass(frozen=True, repr=False) -class HighLevelILRlc(Arithmetic, BinaryOperation): - operand_names = tuple(["left", "right", "carry"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) - - @property - def carry(self) -> HighLevelILInstruction: - return self.get_expr(2) +class HighLevelILRlc(Carry): + pass @dataclass(frozen=True, repr=False) @@ -1272,28 +1577,12 @@ class HighLevelILMul(Arithmetic, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILMulu_dp(BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILMuls_dp(Signed, BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) @@ -1303,15 +1592,7 @@ class HighLevelILDivu(Arithmetic, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILDivu_dp(BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) @@ -1321,15 +1602,7 @@ class HighLevelILDivs(Signed, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILDivs_dp(Signed, BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) @@ -1339,15 +1612,7 @@ class HighLevelILModu(Arithmetic, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILModu_dp(BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) @@ -1357,65 +1622,36 @@ class HighLevelILMods(Signed, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILMods_dp(Signed, BinaryOperation, DoublePrecision): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILNeg(Arithmetic, UnaryOperation): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + pass @dataclass(frozen=True, repr=False) class HighLevelILNot(Arithmetic, UnaryOperation): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + pass @dataclass(frozen=True, repr=False) class HighLevelILSx(Arithmetic, UnaryOperation): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + pass @dataclass(frozen=True, repr=False) class HighLevelILZx(Arithmetic, UnaryOperation): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + pass @dataclass(frozen=True, repr=False) class HighLevelILLow_part(Arithmetic, UnaryOperation): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) + pass @dataclass(frozen=True, repr=False) class HighLevelILCall(Call): - operand_names = tuple(["dest", "params"]) @property def dest(self) -> HighLevelILInstruction: @@ -1425,10 +1661,20 @@ class HighLevelILCall(Call): def params(self) -> List[HighLevelILInstruction]: return self.get_expr_list(1, 2) + @property + def vars_read(self) -> VariablesList: + return [*self.dest.vars_referenced, *[v for i in self.params for v in i.vars_referenced]] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.params] + @dataclass(frozen=True, repr=False) class HighLevelILCall_ssa(Call, SSA): - operand_names = tuple(["dest", "params", "dest_memory", "src_memory"]) @property def dest(self) -> HighLevelILInstruction: @@ -1446,157 +1692,76 @@ class HighLevelILCall_ssa(Call, SSA): def src_memory(self) -> int: return self.get_int(4) - -@dataclass(frozen=True, repr=False) -class HighLevelILCmp_e(Comparison): - operand_names = tuple(["left", "right"]) - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) + def vars_read(self) -> VariablesList: + return [*self.dest.vars_referenced, *[v for i in self.params for v in i.vars_referenced]] @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + def vars_referenced(self) -> VariablesList: + return self.vars_read + + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.params, self.dest_memory, self.src_memory] @dataclass(frozen=True, repr=False) -class HighLevelILCmp_ne(Comparison): - operand_names = tuple(["left", "right"]) +class HighLevelILCmp_e(Comparison): + pass - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) +@dataclass(frozen=True, repr=False) +class HighLevelILCmp_ne(Comparison): + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_slt(Comparison, Signed): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_ult(Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_sle(Comparison, Signed): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_ule(Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_sge(Comparison, Signed): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_uge(Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_sgt(Comparison, Signed): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILCmp_ugt(Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILTest_bit(Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) -class HighLevelILBool_to_int(HighLevelILInstruction): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILBool_to_int(UnaryOperation): + pass @dataclass(frozen=True, repr=False) @@ -1606,16 +1771,25 @@ class HighLevelILAdd_overflow(Arithmetic, BinaryOperation): @dataclass(frozen=True, repr=False) class HighLevelILSyscall(Call): - operand_names = tuple(["params"]) @property def params(self) -> List[HighLevelILInstruction]: return self.get_expr_list(0, 1) + @property + def vars_read(self) -> VariablesList: + return [v for i in self.params for v in i.vars_referenced] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + def operands(self) -> List[HighLevelILOperandType]: + return [self.params] + @dataclass(frozen=True, repr=False) class HighLevelILSyscall_ssa(Call, SSA): - operand_names = tuple(["params", "dest_memory", "src_memory"]) @property def params(self) -> List[HighLevelILInstruction]: @@ -1629,10 +1803,20 @@ class HighLevelILSyscall_ssa(Call, SSA): def src_memory(self) -> int: return self.get_int(3) + @property + def vars_read(self) -> VariablesList: + return [v for i in self.params for v in i.vars_referenced] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + def operands(self) -> List[HighLevelILOperandType]: + return [self.params, self.dest_memory, self.src_memory] + @dataclass(frozen=True, repr=False) class HighLevelILTailcall(Tailcall): - operand_names = tuple(["dest", "params"]) @property def dest(self) -> HighLevelILInstruction: @@ -1642,24 +1826,39 @@ class HighLevelILTailcall(Tailcall): def params(self) -> List[HighLevelILInstruction]: return self.get_expr_list(1, 2) + @property + def vars_read(self) -> VariablesList: + return [*self.dest.vars_referenced, *[v for i in self.params for v in i.vars_referenced]] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.dest, self.params] + + @dataclass(frozen=True, repr=False) class HighLevelILBp(Terminal): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) class HighLevelILTrap(Terminal): - operand_names = tuple(["vector"]) @property def vector(self) -> int: return self.get_int(0) + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.vector] + @dataclass(frozen=True, repr=False) class HighLevelILIntrinsic(HighLevelILInstruction): - operand_names = tuple(["intrinsic", "params"]) @property def intrinsic(self) -> 'lowlevelil.ILIntrinsic': @@ -1669,10 +1868,21 @@ class HighLevelILIntrinsic(HighLevelILInstruction): def params(self) -> List[HighLevelILInstruction]: return self.get_expr_list(1, 2) + @property + def vars_read(self) -> VariablesList: + return [v for i in self.params for v in i.vars_referenced] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.intrinsic, self.params] + @dataclass(frozen=True, repr=False) class HighLevelILIntrinsic_ssa(SSA): - operand_names = tuple(["intrinsic", "params", "dest_memory", "src_memory"]) @property def intrinsic(self) -> 'lowlevelil.ILIntrinsic': @@ -1690,270 +1900,142 @@ class HighLevelILIntrinsic_ssa(SSA): def src_memory(self) -> int: return self.get_int(3) + @property + def vars_read(self) -> VariablesList: + return [v for i in self.params for v in i.vars_referenced] + + @property + def vars_referenced(self) -> VariablesList: + return self.vars_read + + @property + def operands(self) -> List[HighLevelILOperandType]: + return [self.intrinsic, self.params, self.dest_memory, self.src_memory] + @dataclass(frozen=True, repr=False) class HighLevelILUndef(Terminal): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) class HighLevelILUnimpl(HighLevelILInstruction): - operand_names = tuple() + pass @dataclass(frozen=True, repr=False) -class HighLevelILUnimpl_mem(Memory): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILUnimpl_mem(Memory, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFadd(FloatingPoint): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) +class HighLevelILFadd(FloatingPoint, BinaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFsub(FloatingPoint): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) +class HighLevelILFsub(FloatingPoint, BinaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFmul(FloatingPoint): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) +class HighLevelILFmul(FloatingPoint, BinaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFdiv(FloatingPoint): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) +class HighLevelILFdiv(FloatingPoint, BinaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFsqrt(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFsqrt(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFneg(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFneg(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFabs(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFabs(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFloat_to_int(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFloat_to_int(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILInt_to_float(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILInt_to_float(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFloat_conv(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFloat_conv(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILRound_to_int(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILRound_to_int(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFloor(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFloor(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILCeil(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILCeil(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) -class HighLevelILFtrunc(FloatingPoint): - operand_names = tuple(["src"]) - - @property - def src(self) -> HighLevelILInstruction: - return self.get_expr(0) +class HighLevelILFtrunc(FloatingPoint, UnaryOperation): + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_e(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_ne(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_lt(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_le(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_ge(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_gt(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_o(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass @dataclass(frozen=True, repr=False) class HighLevelILFcmp_uo(FloatingPoint, Comparison): - operand_names = tuple(["left", "right"]) - - @property - def left(self) -> HighLevelILInstruction: - return self.get_expr(0) - - @property - def right(self) -> HighLevelILInstruction: - return self.get_expr(1) + pass ILInstruction = { diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index fc685533..02f4a70c 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -772,6 +772,7 @@ class SetVar(MediumLevelILInstruction): assert False, "SetVar.src returned object other than, Variable, SSAVariable" return result + @dataclass(frozen=True, repr=False) class FloatingPoint(MediumLevelILInstruction): pass diff --git a/python/types.py b/python/types.py index ddaa5384..4d1ba869 100644 --- a/python/types.py +++ b/python/types.py @@ -45,7 +45,7 @@ OffsetWithConfidenceType = Union[int, 'OffsetWithConfidence'] ParamsType = Union[List['Type'], List['FunctionParameter'], List[Tuple['Type', str]]] MembersType = Union[List['StructureMember'], List[Tuple['Type', str]]] EnumMembersType = Union[List[Tuple[str,int]], List[str], List['EnumerationMember']] -SomeType = Union['MutableType', 'Type'] +SomeType = Union['TypeBuilder', 'Type'] TypeContainer = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary'] # The following are needed to prevent the type checker from getting # confused as we have member functions in `Type` named the same thing @@ -235,11 +235,11 @@ class Symbol: namespace = namespace._get_core_struct() _handle = core.BNCreateSymbol(sym_type, short_name, full_name, raw_name, addr, binding, namespace, ordinal) assert _handle is not None - self.handle = _handle + self._handle = _handle def __del__(self): if core is not None: - core.BNFreeSymbol(self.handle) + core.BNFreeSymbol(self._handle) def __repr__(self): return "<%s: \"%s\" @ %#x>" % (self.type, self.full_name, self.address) @@ -247,7 +247,7 @@ class Symbol: def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) + return ctypes.addressof(self._handle.contents) == ctypes.addressof(other._handle.contents) def __ne__(self, other): if not isinstance(other, self.__class__): @@ -255,22 +255,22 @@ class Symbol: return not (self == other) def __hash__(self): - return hash(ctypes.addressof(self.handle.contents)) + return hash(ctypes.addressof(self._handle.contents)) @property def type(self): """Symbol type (read-only)""" - return SymbolType(core.BNGetSymbolType(self.handle)) + return SymbolType(core.BNGetSymbolType(self._handle)) @property def binding(self): """Symbol binding (read-only)""" - return SymbolBinding(core.BNGetSymbolBinding(self.handle)) + return SymbolBinding(core.BNGetSymbolBinding(self._handle)) @property def namespace(self): """Symbol namespace (read-only)""" - ns = core.BNGetSymbolNameSpace(self.handle) + ns = core.BNGetSymbolNameSpace(self._handle) result = NameSpace._from_core_struct(ns) core.BNFreeNameSpace(ns) return result @@ -278,36 +278,36 @@ class Symbol: @property def name(self): """Symbol name (read-only)""" - return core.BNGetSymbolRawName(self.handle) + return core.BNGetSymbolRawName(self._handle) @property def short_name(self): """Symbol short name (read-only)""" - return core.BNGetSymbolShortName(self.handle) + return core.BNGetSymbolShortName(self._handle) @property def full_name(self): """Symbol full name (read-only)""" - return core.BNGetSymbolFullName(self.handle) + return core.BNGetSymbolFullName(self._handle) @property def raw_name(self): """Symbol raw name (read-only)""" - return core.BNGetSymbolRawName(self.handle) + return core.BNGetSymbolRawName(self._handle) @property def address(self): """Symbol address (read-only)""" - return core.BNGetSymbolAddress(self.handle) + return core.BNGetSymbolAddress(self._handle) @property def ordinal(self): """Symbol ordinal (read-only)""" - return core.BNGetSymbolOrdinal(self.handle) + return core.BNGetSymbolOrdinal(self._handle) @property def auto(self): - return core.BNIsSymbolAutoDefined(self.handle) + return core.BNIsSymbolAutoDefined(self._handle) @dataclass @@ -346,6 +346,13 @@ class OffsetWithConfidence: def from_core_struct(cls, core_struct:core.BNOffsetWithConfidence) -> 'OffsetWithConfidence': return cls(core_struct.value, core_struct.confidence) + @staticmethod + def get_core_struct(value:OffsetWithConfidenceType) -> core.BNOffsetWithConfidence: + if isinstance(value, OffsetWithConfidence): + return value.to_core_struct() + else: + return OffsetWithConfidence(value).to_core_struct() + @dataclass(frozen=True) class BoolWithConfidence: @@ -365,116 +372,965 @@ class BoolWithConfidence: def from_core_struct(cls, core_struct:core.BNBoolWithConfidence) -> 'BoolWithConfidence': return cls(core_struct.value, core_struct.confidence) + @staticmethod + def get_core_struct(value:BoolWithConfidenceType) -> core.BNBoolWithConfidence: + if isinstance(value, BoolWithConfidence): + return value.to_core_struct() + else: + return BoolWithConfidence(value).to_core_struct() + @dataclass(frozen=True) -class MemberAccessWithConfidence: - value:MemberAccess +class SizeWithConfidence: + value:int confidence:int=core.max_confidence - def to_core_struct(self) -> core.BNMemberAccessWithConfidence: - result = core.BNMemberAccessWithConfidence() + def __int__(self): + return self.value + + def to_core_struct(self) -> core.BNSizeWithConfidence: + result = core.BNSizeWithConfidence() result.value = self.value result.confidence = self.confidence return result @classmethod - def from_core_struct(cls, core_struct:core.BNMemberAccessWithConfidence) -> 'MemberAccessWithConfidence': + def from_core_struct(cls, core_struct:core.BNSizeWithConfidence) -> 'SizeWithConfidence': return cls(core_struct.value, core_struct.confidence) + @staticmethod + def get_core_struct(value:SizeWithConfidenceType) -> core.BNSizeWithConfidence: + if isinstance(value, SizeWithConfidence): + return value.to_core_struct() + else: + return SizeWithConfidence(value).to_core_struct() -@dataclass(frozen=True) -class MemberScopeWithConfidence: - value:MemberScope - confidence:int=core.max_confidence - def to_core_struct(self) -> core.BNMemberScopeWithConfidence: - result = core.BNMemberScopeWithConfidence() - result.value = self.value - result.confidence = self.confidence - return result +@dataclass +class MutableTypeBuilder: + type:'TypeBuilder' + container:TypeContainer + name:QualifiedName + platform:Optional['_platform.Platform'] + confidence:int + user:bool = True - @classmethod - def from_core_struct(cls, core_struct:core.BNMemberScopeWithConfidence) -> 'MemberScopeWithConfidence': - return cls(core_struct.value, core_struct.confidence) + def __enter__(self): + return self.type + def __exit__(self, type, value, traceback): + if isinstance(self.container, binaryview.BinaryView): + if self.user: + self.container.define_user_type(self.name, self.type.immutable_copy()) + else: + type_id = types.Type.generate_auto_type_id(str(uuid.uuid4()), str(self.name)) + self.container.define_type(type_id, self.name, self.type.immutable_copy()) + else: + self.container.add_named_type(self.name, self.type.immutable_copy()) -@dataclass(frozen=True) -class SizeWithConfidence: - value:int - confidence:int=core.max_confidence - def __int__(self): - return self.value +class TypeBuilder: + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + self._handle = handle + self.platform = platform + self.confidence = confidence - def to_core_struct(self) -> core.BNSizeWithConfidence: - result = core.BNSizeWithConfidence() - result.value = self.value - result.confidence = self.confidence - return result + def __del__(self): + if core is not None: + core.BNFreeTypeBuilder(self._handle) + + def immutable_copy(self): + Types = { + TypeClass.VoidTypeClass:VoidType, + TypeClass.BoolTypeClass:BoolType, + TypeClass.IntegerTypeClass:IntegerType, + TypeClass.FloatTypeClass:FloatType, + TypeClass.StructureTypeClass:StructureType, + TypeClass.EnumerationTypeClass:EnumerationType, + TypeClass.PointerTypeClass:PointerType, + TypeClass.ArrayTypeClass:ArrayType, + TypeClass.FunctionTypeClass:FunctionType, + TypeClass.NamedTypeReferenceClass:NamedTypeReferenceType, + TypeClass.WideCharTypeClass:WideCharType, + } + return Types[self.type_class](core.BNFinalizeTypeBuilder(self._handle), + self.platform, self.confidence) + + def mutable_copy(self) -> 'TypeBuilder': + return self @classmethod - def from_core_struct(cls, core_struct:core.BNSizeWithConfidence) -> 'SizeWithConfidence': - return cls(core_struct.value, core_struct.confidence) + def create(cls): + _ = cls + return NotImplemented + + @classmethod + def builder(cls, container:TypeContainer, name:'QualifiedName', user:bool=True, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'MutableTypeBuilder': + return MutableTypeBuilder(cls.create(), container, name, platform, confidence, user) + + @staticmethod + def void() -> 'Void': + return Void.create() + + @staticmethod + def bool() -> 'Bool': + return Bool.create() + + @staticmethod + def char(alternate_name:str="") -> 'Char': + return Char.create(alternate_name) + + @staticmethod + def int(width:_int, sign:BoolWithConfidenceType=BoolWithConfidence(True), altname:str="") -> 'Integer': + """ + ``int`` class method for creating an int Type. + :param int width: width of the integer in bytes + :param bool sign: optional variable representing signedness + :param str altname: alternate name for type + """ + return Integer.create(width, sign, altname) + + @staticmethod + def float(width:_int, altname:str="") -> 'Float': + """ + ``float`` class method for creating floating point Types. + :param int width: width of the floating point number in bytes + :param str altname: alternate name for type + """ + return Float.create(width, altname) + + @staticmethod + def wide_char(width:_int, altname:str="") -> 'WideChar': + """ + ``wide_char`` class method for creating wide char Types. + :param int width: width of the wide character in bytes + :param str altname: alternate name for type + """ + return WideChar.create(width, altname) + + @staticmethod + def named_type_from_type(name:QualifiedName, type:'Type') -> 'NamedTypeReference': + return NamedTypeReference.named_type_from_type(name, type) + + @staticmethod + def named_type_from_type_and_id(type_id:str, name:QualifiedName, type:'Type') -> 'NamedTypeReference': + return NamedTypeReference.named_type_from_type_and_id(type_id, name, type) + + @staticmethod + def generate_named_type_reference(guid:str, name:QualifiedName): + return NamedTypeReference.generate_named_type_reference(guid, name) + + @staticmethod + def named_type_from_registered_type(view:'binaryview.BinaryView', name:QualifiedName) -> 'NamedTypeReference': + return NamedTypeReference.named_type_from_registered_type(view, name) + + @staticmethod + def pointer(type:'Type', arch:'architecture.Architecture'=None, + const:BoolWithConfidenceType=BoolWithConfidence(False), + volatile:BoolWithConfidenceType=BoolWithConfidence(False), + ref_type:ReferenceType=ReferenceType.PointerReferenceType, width:_int=None) -> 'Pointer': + if arch is not None: + width = arch.address_size + if width is None: + raise TypeCreateException("Must specify either an architecture or a width to create a pointer") + + return Pointer.create(type, width, arch, const, volatile, ref_type) + + @staticmethod + def array(type:'Type', count:_int) -> 'Array': + return Array.create(type, count) + + @staticmethod + def function(ret:Optional['Type'], params:ParamsType=[], calling_convention:'callingconvention.CallingConvention'=None, + variable_arguments:BoolWithConfidenceType=BoolWithConfidence(False), + stack_adjust:SizeWithConfidenceType=0) -> 'Function': + """ + ``function`` class method for creating an function Type. + :param Type ret: return Type of the function + :param params: list of parameter Types + :type params: list(Type) + :param CallingConvention calling_convention: optional argument for the function calling convention + :param bool variable_arguments: optional boolean, true if the function has a variable number of arguments + """ + if ret is None: + ret = Type.void() + return Function.create(ret, calling_convention, params, variable_arguments, stack_adjust) + + + @staticmethod + def structure(members:MembersType=[], packed:_bool=False, type:StructureVariant=StructureVariant.StructStructureType) -> 'Structure': + return Structure.create(members, type, packed) + + @staticmethod + def enumeration(arch:Optional['architecture.Architecture']=None, members:EnumMembersType=[], + width:_int=4, sign:BoolWithConfidenceType=BoolWithConfidence(False)) -> 'Enumeration': + return Enumeration.create(members, width, arch, sign) + + @staticmethod + def named_type_reference(name:QualifiedName, type:Optional['Type']=None, guid:Optional[str]=None): + """ + Deprecated property kept for backward compability. + These operations can now be done directly on the Type object. + """ + return NamedTypeReferenceType.create_from_type(name, type, guid) -class _TypeBuilder: - def __init__(self, handle, **kwargs): - assert isinstance(handle.contents, core.BNTypeBuilder), "Attempting to create mutable Type" - self.handle = handle - core.BNTypeBuilderSetConst(self.handle, kwargs.get("const", BoolWithConfidence(False)).to_core_struct()) - core.BNTypeBuilderSetVolatile(self.handle, kwargs.get("volatile", BoolWithConfidence(False)).to_core_struct()) - core.BNSetFunctionTypeBuilderCanReturn(self.handle, kwargs.get("can_return", BoolWithConfidence(False).to_core_struct())) - core.BNTypeBuilderSetMemberScope(self.handle, kwargs.get("member_scope", MemberScopeWithConfidence(MemberScope.NoScope).to_core_struct())) - core.BNTypeBuilderSetMemberAccess(self.handle, kwargs.get("member_access", MemberAccessWithConfidence(MemberAccess.NoAccess).to_core_struct())) + @property + def width(self) -> _int: + return core.BNGetTypeBuilderWidth(self._handle) + + def __len__(self): + return self.width - def finalize(self): - type_handle = core.BNFinalizeTypeBuilder(self.handle) + @property + def finalized(self): + type_handle = core.BNFinalizeTypeBuilder(self._handle) assert type_handle is not None, "core.BNFinalizeTypeBuilder returned None" return type_handle @property def const(self) -> BoolWithConfidence: """Whether type is const (read/write)""" - result = core.BNIsTypeBuilderConst(self.handle) + result = core.BNIsTypeBuilderConst(self._handle) return BoolWithConfidence(result.value, confidence = result.confidence) @const.setter def const(self, value:BoolWithConfidence) -> None: - core.BNTypeBuilderSetConst(self.handle, value.to_core_struct()) + core.BNTypeBuilderSetConst(self._handle, value.to_core_struct()) @property def volatile(self) -> BoolWithConfidence: """Whether type is volatile (read/write)""" - result = core.BNIsTypeBuilderVolatile(self.handle) + result = core.BNIsTypeBuilderVolatile(self._handle) return BoolWithConfidence(result.value, confidence = result.confidence) @volatile.setter def volatile(self, value:BoolWithConfidence) -> None: - core.BNTypeBuilderSetVolatile(self.handle, value.to_core_struct()) + core.BNTypeBuilderSetVolatile(self._handle, value.to_core_struct()) + + @property + def alignment(self) -> _int: + return core.BNGetTypeBuilderAlignment(self._handle) + + def _child(self, platform:'_platform.Platform'=None, confidence:_int=core.max_confidence) -> 'Type': + return Type.create(core.BNNewTypeReference(core.BNGetTypeBuilderChildType(self._handle)), platform, confidence) + + @property + def alternate_name(self) -> str: + return core.BNGetTypeBuilderAlternateName(self._handle) + + @alternate_name.setter + def alternate_name(self, name:str) -> None: + return core.BNTypeBuilderSetAlternateName(self._handle, name) + + @property + def type_class(self) -> TypeClass: + return TypeClass(core.BNGetTypeBuilderClass(self._handle)) + + +class Void(TypeBuilder): + @classmethod + def create(cls, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Void': + return cls(core.BNCreateVoidTypeBuilder(), platform, confidence) + + +class Bool(TypeBuilder): + @classmethod + def create(cls, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Bool': + handle = core.BNCreateBoolTypeBuilder() + assert handle is not None, "core.BNCreateBoolTypeBuilder returned None" + return cls(handle, platform, confidence) + + +class Integer(TypeBuilder): + @classmethod + def create(cls, width:int, sign:BoolWithConfidenceType=True, alternate_name:str="", + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Integer': + _sign = BoolWithConfidence.get_core_struct(sign) + return cls(core.BNCreateIntegerTypeBuilder(width, _sign, alternate_name), platform, confidence) + + @property + def signed(self) -> BoolWithConfidence: + """Whether type is signed (read/write)""" + result = core.BNIsTypeBuilderSigned(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + @signed.setter + def signed(self, value:BoolWithConfidenceType) -> None: # type: ignore + _value = value + if isinstance(_value, bool): + _value = BoolWithConfidence(_value) + core.BNTypeBuilderSetSigned(self._handle, _value.to_core_struct()) + + +class Char(Integer): + @classmethod + def create(cls, alternate_name:str="", + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Char': + return cls(core.BNCreateIntegerTypeBuilder(1, False, alternate_name), platform, confidence) + + +class Float(TypeBuilder): + @classmethod + def create(cls, width:int, alternate_name:str="", + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Float': + return cls(core.BNCreateFloatTypeBuilder(width, alternate_name), platform, confidence) + + +class WideChar(TypeBuilder): + @classmethod + def create(cls, width:int, alternate_name:str="", + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'WideChar': + return cls(core.BNCreateWideCharTypeBuilder(width, alternate_name), platform, confidence) + + +class Pointer(TypeBuilder): + @classmethod + def create(cls, type:'Type', width:int=4, arch:Optional['architecture.Architecture']=None, + const:BoolWithConfidenceType=False, volatile:BoolWithConfidenceType=False, + ref_type:ReferenceType=ReferenceType.PointerReferenceType, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Pointer': + assert width is not None or arch is not None, "Must specify either a width or architecture when creating a pointer" + _width = width + if arch is not None: + _width = arch.address_size + + _const = BoolWithConfidence.get_core_struct(const) + _volatile = BoolWithConfidence.get_core_struct(volatile) + + return cls(core.BNCreatePointerTypeBuilderOfWidth(_width, type.immutable_copy().handle, _const, + _volatile, ref_type), platform, confidence) + + @property + def target(self) -> 'TypeBuilder': + return self.immutable_target.mutable_copy() + + @property + def immutable_target(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Type': + return self._child(platform, confidence) + + +class Array(TypeBuilder): + @classmethod + def create(cls, type:SomeType, element_count:int, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Array': + return cls(core.BNCreateArrayTypeBuilder(type.immutable_copy().handle, element_count), platform, confidence) + + @property + def count(self) -> int: + return core.BNGetTypeBuilderElementCount(self._handle) + + @property + def element_type(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + return self._child(platform, confidence) + + +class Function(TypeBuilder): + @classmethod + def create(cls, return_type:SomeType, calling_convention:Optional['callingconvention.CallingConvention']=None, + params:ParamsType=[], var_args:BoolWithConfidenceType=False, + stack_adjust:SizeWithConfidenceType=0, platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'Function': + param_buf = (core.BNFunctionParameter * len(params))() + for i in range(0, len(params)): + param = params[i] + if isinstance(param, Type): + param_buf[i].name = "" + param_buf[i].type = param.handle + param_buf[i].typeConfidence = param.confidence + param_buf[i].defaultLocation = True + elif isinstance(param, FunctionParameter): + t = param.type.immutable_copy() + param_buf[i].name = param.name + param_buf[i].type = t.handle + param_buf[i].typeConfidence = t.confidence + if param.location is None: + param_buf[i].defaultLocation = True + else: + param_buf[i].defaultLocation = False + param_buf[i].location.type = param.location.source_type + param_buf[i].location.index = param.location.index + param_buf[i].location.storage = param.location.storage + else: + param_buf[i].name = param[1] + param_buf[i].type = param[0].handle + param_buf[i].typeConfidence = param[0].confidence + param_buf[i].defaultLocation = True + + ret_conf = return_type.immutable_copy().to_core_struct() + conv_conf = core.BNCallingConventionWithConfidence() + if calling_convention is None: + conv_conf.convention = None + conv_conf.confidence = 0 + else: + conv_conf.convention = calling_convention.handle + conv_conf.confidence = calling_convention.confidence + + vararg_conf = BoolWithConfidence.get_core_struct(var_args) + stack_adjust_conf = SizeWithConfidence.get_core_struct(stack_adjust) + + return cls(core.BNCreateFunctionTypeBuilder(ret_conf, conv_conf, param_buf, len(params), + vararg_conf, stack_adjust_conf), platform, confidence) + + @property + def immutable_return_value(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'Type': + return self._child(platform, confidence) + + @property + def return_value(self) -> TypeBuilder: + return self.immutable_return_value.mutable_copy() + + @return_value.setter + def return_value(self, value:SomeType): # type: ignore + self._return_type = value.mutable_copy() # TODO: Fix me + + def append(self, type:Union[SomeType, FunctionParameter], name:str=""): + params = self.parameters + if isinstance(type, FunctionParameter): + self.parameters.append(type.mutable_copy()) + else: + self.parameters.append(FunctionParameter(type.mutable_copy(), name)) + self.params = params @property - def can_return(self): - core.BNFunctionTypeBuilderCanReturn(self.handle) + def calling_convention(self) -> 'callingconvention.CallingConvention': + return callingconvention.CallingConvention(core.BNNewCallingConventionReference(core.BNGetTypeBuilderCallingConvention(self._handle))) + + @property + def can_return(self) -> bool: + return core.BNFunctionTypeBuilderCanReturn(self._handle) @can_return.setter - def can_return(self, value): - core.BNSetFunctionTypeBuilderCanReturn(self.handle, value) + def can_return(self, value:BoolWithConfidenceType) -> None: # type: ignore + _value = value + if isinstance(_value, bool): + _value = BoolWithConfidence(_value) + core.BNSetFunctionTypeBuilderCanReturn(self._handle, _value) + + @property + def stack_adjust(self) -> OffsetWithConfidence: + return OffsetWithConfidence.from_core_struct(core.BNGetTypeBuilderStackAdjustment(self._handle)) + + @property + def parameters(self) -> List[FunctionParameter]: + """Type parameters list (read-only)""" + count = ctypes.c_ulonglong() + params = core.BNGetTypeBuilderParameters(self._handle, count) + assert params is not None, "core.BNGetTypeBuilderParameters returned None" + result = [] + for i in range(0, count.value): + param_type = Type.create(core.BNNewTypeReference(params[i].type), platform = self.platform, confidence = params[i].typeConfidence) + if params[i].defaultLocation: + param_location = None + else: + name = params[i].name + if (params[i].location.type == VariableSourceType.RegisterVariableSourceType) and (self.platform is not None): + name = self.platform.arch.get_reg_name(params[i].location.storage) + elif params[i].location.type == VariableSourceType.StackVariableSourceType: + name = "arg_%x" % params[i].location.storage + param_location = variable.VariableNameAndType(params[i].location.type, params[i].location.index, + params[i].location.storage, name, param_type) + result.append(FunctionParameter(param_type, params[i].name, param_location)) + core.BNFreeTypeParameterList(params, count.value) + return result + + @staticmethod + def _to_api_object(params:List[FunctionParameter]): + param_buf = (core.BNFunctionParameter * len(params))() + for i in range(0, len(params)): + param = params[i] + if isinstance(param, Type): + param_buf[i].name = "" + param_buf[i].type = param.handle + param_buf[i].typeConfidence = param.confidence + param_buf[i].defaultLocation = True + elif isinstance(param, FunctionParameter): + t = param.type.immutable_copy() + param_buf[i].name = param.name + param_buf[i].type = t.handle + param_buf[i].typeConfidence = t.confidence + if param.location is None: + param_buf[i].defaultLocation = True + else: + param_buf[i].defaultLocation = False + param_buf[i].location.type = param.location.source_type + param_buf[i].location.index = param.location.index + param_buf[i].location.storage = param.location.storage + else: + param_buf[i].name = param[1] + param_buf[i].type = param[0].handle + param_buf[i].typeConfidence = param[0].confidence + param_buf[i].defaultLocation = True + + @parameters.setter + def parameters(self, params:List[FunctionParameter]) -> None: + core.BNSetFunctionTypeBuilderParameters(self._handle, Function._to_api_object(params), len(params)) + + +@dataclass +class StructureMember: + type:Union['Type', TypeBuilder] + name:str + offset:int + access:MemberAccess = MemberAccess.NoAccess + scope:MemberScope = MemberScope.NoScope + + def __post_init__(self): + self.type = self.type.mutable_copy() + + def __repr__(self): + # TODO: Consider showing this differently if the type is mutable + if len(self.name) == 0: + return f"<member: {self.type.immutable_copy()}, offset {self.offset:#x}>" + return f"<{self.type.immutable_copy().get_string_before_name()} {self.name}{self.type.immutable_copy().get_string_after_name()}" + \ + f", offset {self.offset:#x}>" + # return f"<StructureMember: {self.type} {self.name}>" + + def __len__(self): + return len(self.type) + + +class Structure(TypeBuilder): + def __init__(self, handle, builder_handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + super(Structure, self).__init__(handle, platform, confidence) + self.builder_handle = builder_handle + + @classmethod + def create(cls, members:MembersType=[], + type:StructureVariant=StructureVariant.StructStructureType, + packed:bool=False, + width:Optional[int]=None, platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'Structure': + builder_handle = core.BNCreateStructureBuilderWithOptions(type, packed) + if width is not None: + core.BNSetStructureBuilderWidth(builder_handle) + for member in members: + if isinstance(member, Tuple): + _type, _name = member + core.BNAddStructureBuilderMember(builder_handle, _type.immutable_copy().to_core_struct(), _name, MemberAccess.NoAccess, MemberScope.NoScope) + elif isinstance(member, StructureMember): + core.BNAddStructureBuilderMemberAtOffset(builder_handle, member.type.immutable_copy().to_core_struct(), + member.name, member.offset, False, member.access, member.scope) + + struct = core.BNFinalizeStructureBuilder(builder_handle) + return cls(core.BNCreateStructureTypeBuilder(struct), builder_handle, platform, confidence) + + def _update_refs(self): + if self._handle is not None: + core.BNFreeTypeBuilder(self._handle) + struct = core.BNFinalizeStructureBuilder(self.builder_handle) + assert struct is not None, "core.BNFinalizeStructureBuilder returned None" + self._handle = core.BNCreateStructureTypeBuilder(struct) + + @property + def members(self) -> List[StructureMember]: + """Structure member list (read-only)""" + count = ctypes.c_ulonglong() + members = core.BNGetStructureBuilderMembers(self.builder_handle, count) + assert members is not None, "core.BNGetStructureBuilderMembers returned None" + try: + result = [] + for i in range(0, count.value): + result.append(StructureMember(Type.create(core.BNNewTypeReference(members[i].type), confidence=members[i].typeConfidence), + members[i].name, members[i].offset)) + finally: + core.BNFreeStructureMemberList(members, count.value) + + return result + + @members.setter + def members(self, members:List[StructureMember]) -> None: + for i in range(len(self.members)): + core.BNRemoveStructureBuilderMember(i) + + for member in members: + core.BNAddStructureBuilderMember(self.builder_handle, member.type.immutable_copy().to_core_struct(), + member.name, member.access, member.scope) + + self._update_refs() + + @property + def packed(self) -> bool: + return core.BNIsStructureBuilderPacked(self.builder_handle) + + @packed.setter + def packed(self, value:bool) -> None: + core.BNSetStructureBuilderPacked(self.builder_handle, value) + self._update_refs() + + @property + def alignment(self) -> int: + return core.BNGetStructureBuilderAlignment(self.builder_handle) + + @alignment.setter + def alignment(self, value:int) -> None: + core.BNSetStructureBuilderAlignment(self.builder_handle, value) + self._update_refs() + + @property + def width(self) -> int: + return core.BNGetStructureBuilderWidth(self.builder_handle) + + @width.setter + def width(self, value:int) -> None: + core.BNSetStructureBuilderWidth(self.builder_handle, value) + self._update_refs() + + @property + def union(self) -> bool: + return core.BNIsStructureBuilderUnion(self.builder_handle) + + @property + def type(self) -> StructureVariant: + return StructureVariant(core.BNGetStructureBuilderType(self.builder_handle)) + + @type.setter + def type(self, value:StructureVariant) -> None: + core.BNSetStructureBuilderType(self.builder_handle, value) + self._update_refs() + + def __repr__(self): + return f"<struct: size {self.width:#x}>" + + def __getitem__(self, name:str) -> Optional[StructureMember]: + member = core.BNGetStructureBuilderMemberByName(self._handle, name) + if member is None: + return None + try: + return StructureMember(Type(core.BNNewTypeReference(member.contents.type), + confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) + finally: + core.BNFreeStructureMember(member) + + def __iter__(self) -> Generator[StructureMember, None, None]: + for member in self.members: + yield member + + def __len__(self) -> int: + return self.width + + def member_at_offset(self, offset:int) -> Optional[StructureMember]: + for member in self.members: + if member.offset == offset: + return member + return None + + def index_by_name(self, name:MemberName) -> Optional[MemberIndex]: + for i, member in enumerate(self.members): + if member.name == name: + return i + return None + + def index_by_offset(self, offset:MemberOffset) -> Optional[MemberIndex]: + for i, member in enumerate(self.members): + if member.offset == offset: + return i + return None + + def index_from(self, index:Optional[MemberIndex]=None, name:Optional[MemberName]=None, offset:Optional[MemberOffset]=None) -> MemberIndex: + if index is not None: + if index >= len(self.members): + raise IndexError("list index out of range") + elif name is not None: + index = self.index_by_name(name) + if index is None: + raise ValueError(f"StructureMember {name} doesn't exist") + elif offset is not None: + index = self.index_by_offset(offset) + if index is None: + raise ValueError(f"No StructureMember at offset exists") + else: + raise ValueError("One of the following must") + + return index + + # def erase(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: + # # removes the specified item shrinking the total size of the structure and adjusting + # # the offset of any members with offsets greater than the offset of member[index]. + # # In the case where there are multiple members which overlap the erased item they will be erased too + # # but the structure will only be shrunken by the specified member's width + # # raise exception if the index doesn't exist + # # raises exception if more not exactly one of index/name/offset are not None + # item = self.members[self.index_from(index, name, offset)] + # self.clear_members(item.offset, len(item)) + # self.adjust_space(item.offset, -len(item)) + + # def clear(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: + # # clears the member at the index/member-name. No adjustment is made to other members or the structure's size + # # raise exception if the index doesn't exist + # del self.members[self.index_from(index, name, offset)] + + # def clear_members(self, offset:MemberOffset, size:int) -> None: + # # clears members which overlap offset + # to_clear = [] + # for i, member in enumerate(self.members): + # if member.offset >= offset and member.offset < offset + size: + # to_clear.append(i) + # elif member.offset < offset and member.offset + len(member) > offset: + # to_clear.append(i) + # for i in to_clear: + # self.clear(index=i) + + # def replace_member(self, new_name:MemberName, type:SomeType, index:MemberIndex=None, old_name:MemberName=None, offset:MemberOffset=None) -> None: + # # replaces any members within the structure which overlap member[index] + # index = self.index_from(index, old_name, offset) + # item = self.members[index] + # self.clear_members(item.offset, len(item)) + # self.members.insert(index, StructureMember(type, new_name, item.offset)) + + def replace(self, index:int, type:'Type', name:str="", overwrite_existing:bool=True): + core.BNReplaceStructureBuilderMember(self.builder_handle, index, + type.to_core_struct(), name, overwrite_existing) + self._update_refs() + + def remove(self, index:int): + core.BNRemoveStructureBuilderMember(self.builder_handle, index) + self._update_refs() + + def insert(self, offset:int, type:'Type', name:str="", overwrite_existing:bool=True, + access:MemberAccess=MemberAccess.NoAccess, scope:MemberScope=MemberScope.NoScope): + core.BNAddStructureBuilderMemberAtOffset(self.builder_handle, + type.to_core_struct(), name, offset, overwrite_existing, access, scope) + self._update_refs() + + def append(self, type:SomeType, name:MemberName="", access:MemberAccess=MemberAccess.NoAccess, + scope:MemberScope=MemberScope.NoScope) -> 'Structure': + # appends a member at the end of the structure growing the structure + core.BNAddStructureBuilderMember(self.builder_handle, + type.immutable_copy().to_core_struct(), name, access, scope) + self._update_refs() + return self + + def add_member_at_offset(self, name:MemberName, type:SomeType, offset:MemberOffset, overwrite_existing:bool=True, + access:MemberAccess=MemberAccess.NoAccess, scope:MemberScope=MemberScope.NoScope) -> 'Structure': + # Adds structure member to the given offset optionally clearing any members within the range offset-offset+len(type) + core.BNAddStructureBuilderMemberAtOffset(self.builder_handle, type.immutable_copy().handle, name, + offset, overwrite_existing, access, scope) + self._update_refs() + return self + + +@dataclass(frozen=True) +class EnumerationMember: + name:str + value:Optional[int] + + def __repr__(self): + value = f"{self.value:#x}" if self.value is not None else "auto()" + return f"<{self.name} = {value}>" + + def __int__(self) -> Optional[int]: + return self.value + + +class Enumeration(TypeBuilder): + def __init__(self, handle, enum_builder_handle, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + super(Enumeration, self).__init__(handle, platform, confidence) + self.enum_builder_handle = enum_builder_handle + + @staticmethod + def _enum_handle_from_members(members): + enum_builder_handle = core.BNCreateEnumerationBuilder() + for member in members: + if member.value is None: + core.BNAddEnumerationBuilderMember(enum_builder_handle, member.name) + else: + core.BNAddEnumerationBuilderMemberWithValue(enum_builder_handle, member.name, member.value) + + enum_handle = core.BNFinalizeEnumerationBuilder(enum_builder_handle) + assert enum_handle is not None, "core.BNFinalizeEnumerationBuilder returned None" + return core.BNNewEnumerationReference(enum_handle) + + @classmethod + def create(cls, members=List[EnumerationMember], width:int=4, + arch:Optional['architecture.Architecture']=None, sign:BoolWithConfidenceType=False, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + + _width = width + if arch is not None: + _width = arch.address_size + _sign = BoolWithConfidence.get_core_struct(sign) + + enum_builder_handle = Enumeration._enum_handle_from_members(members) + handle = core.BNCreateEnumerationTypeBuilderOfWidth(enum_builder_handle, _width, _sign) + assert handle is not None, "core.BNCreateEnumerationTypeBuilderOfWidth returned None" + return cls(handle, enum_builder_handle, platform, confidence) + + def _update_handles(self): + if self._handle is not None: + self.enum_builder_handle = core.BNDuplicateEnumerationBuilder(self.enum_builder_handle) + # Freeing the type builder will delete the original handle so we must duplicate. + core.BNFreeTypeBuilder(self._handle) + + self.enum_builder_handle = self._enum_handle_from_members + self._handle = core.BNCreateEnumerationTypeBuilderOfWidth(builder, self.width, self.signed) + assert self._handle is not None, "core.BNCreateEnumerationTypeBuilderOfWidth returned None" + + def __del__(self): + core.BNFreeTypeBuilder(self._handle) + # core.BNFreeEnumerationBuilder(self.enum_builder_handle) + + def __repr__(self): + return "<enum: %s>" % repr(self.members) + + @property + def signed(self) -> BoolWithConfidence: + """Whether type is signed (read/write)""" + result = core.BNIsTypeBuilderSigned(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + @signed.setter + def signed(self, value:BoolWithConfidenceType) -> None: # type: ignore + _value = BoolWithConfidence.get_core_struct(value) + core.BNTypeBuilderSetSigned(self._handle, _value) + + @property + def members(self) -> List[EnumerationMember]: + """Enumeration member list (read-only)""" + count = ctypes.c_ulonglong() + members = core.BNGetEnumerationBuilderMembers(self.enum_builder_handle, count) + assert members is not None, "core.BNGetEnumerationBuilderMembers returned None" + result = [] + try: + for i in range(count.value): + result.append(EnumerationMember(members[i].name, members[i].value if not members[i].isDefault else None)) + return result + finally: + core.BNFreeEnumerationMemberList(members, count.value) + + @members.setter + def members(self, members:List[EnumerationMember]) -> None: + if self.enum_builder_handle is not None: + core.BNFreeEnumerationBuilder(self.enum_builder_handle) + self.enum_builder_handle = core.BNCreateEnumerationBuilder() + for member in members: + if member.value is None: + core.BNAddEnumerationBuilderMember(self.enum_builder_handle, member.name) + else: + core.BNAddEnumerationBuilderMemberWithValue(self.enum_builder_handle, member.name, member.value) + self._update_handles() + + def append(self, name:str, value:Optional[int]=None) -> 'Enumeration': + + if value is None: + core.BNAddEnumerationBuilderMember(self.enum_builder_handle, name) + else: + core.BNAddEnumerationBuilderMemberWithValue(self.enum_builder_handle, name, value) + self._update_handles() + return self + + def remove(self, i:int) -> 'Enumeration': + core.BNRemoveEnumerationBuilderMember(self.enum_builder_handle, i) + self._update_handles() + return self + + def replace(self, i:int, name:str, value:Optional[int]=None) -> 'Enumeration': + core.BNReplaceEnumerationBuilderMember(self.enum_builder_handle, i, name, value) + self._update_handles() + return self + + def __iter__(self) -> Generator[EnumerationMember, None, None]: + for i, member in enumerate(self.members): + if member.value is None: + yield EnumerationMember(member.name, i) + else: + yield member + + def __getitem__(self, value:Union[str, int, slice]): + if isinstance(value, str): + for member in self.members: + if member.name == value: + return member + return None + elif isinstance(value, int): + return self.members[value] + elif isinstance(value, slice): # not combined with the previous check due to pyright bug + return self.members[value] + else: + raise ValueError(f"Incompatible type {type(value)} for __getitem__") + + def __setitem__(self, item, value): + if isinstance(item, str): + for i, member in enumerate(self.members): + if member.name == item: + self.replace(i, member.name, value) + elif isinstance(item, int) and isinstance(value, EnumerationMember): + self.replace(item, value.name, value.value) + else: + assert False, "Invalid type for Enumeration.__setitem__" + + +class NamedTypeReference(TypeBuilder): + def __init__(self, id:str, name:QualifiedName, + named_type_class:NamedTypeReferenceClass=NamedTypeReferenceClass.UnknownNamedTypeClass, + width:int = 0, alignment:int = 0, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + self.ntr_handle = core.BNCreateNamedType(named_type_class, id, QualifiedName(name)._get_core_struct()) + self._handle = core.BNCreateNamedTypeReferenceBuilder(self.ntr_handle, width, alignment) + + def __del__(self): + if core is not None: + core.BNFreeNamedTypeReference(self.ntr_handle) + core.BNFreeTypeBuilder(self._handle) @property - def member_scope(self): - core.BNTypeBuilderGetMemberScope(self.handle) + def name(self) -> QualifiedName: + return QualifiedName._from_core_struct(core.BNGetTypeReferenceName(self.ntr_handle)) - @member_scope.setter - def member_scope(self, value): - core.BNTypeBuilderSetMemberScope(self.handle, value) + @property + def id(self) -> str: + return core.BNGetTypeReferenceId(self.ntr_handle) @property - def member_access(self): - core.BNTypeBuilderGetMemberAccess(self.handle) + def named_type_class(self) -> NamedTypeReferenceClass: + return core.BNGetTypeReferenceClass(self.ntr_handle) + + @classmethod + def named_type(cls, named_type:'NamedTypeReference', width:int=0, align:int=1) -> 'NamedTypeReference': + return cls(named_type.id, named_type.name, named_type.named_type_class, width, align) + + @classmethod + def named_type_from_type_and_id(cls, type_id:str, name:QualifiedName, type:'Type') -> 'NamedTypeReference': + if type is None: + return cls(type_id, name) + elif type.type_class == TypeClass.StructureTypeClass: + if type.structure_type == StructureVariant.StructStructureType: + return cls(type_id, name, NamedTypeReferenceClass.StructNamedTypeClass) + elif type.structure_type == StructureVariant.UnionStructureType: + return cls(type_id, name, NamedTypeReferenceClass.UnionNamedTypeClass) + else: + return cls(type_id, name, NamedTypeReferenceClass.ClassNamedTypeClass) + elif type.type_class == TypeClass.EnumerationTypeClass: + return cls(type_id, name, NamedTypeReferenceClass.EnumNamedTypeClass) + else: + return cls(type_id, name, NamedTypeReferenceClass.TypedefNamedTypeClass) + + @classmethod + def named_type_from_type(cls, name, type): + if type is None: + return cls.create(str(uuid.uuid4()), name) + else: + return cls.create(str(uuid.uuid4()), name, NamedTypeReferenceClass.TypedefNamedTypeClass) + + @classmethod + def named_type_from_registered_type(cls, view, name): + type = view.get_type_by_name(name) + if type is None: + raise TypeCreateException(f"Unable to find type named {name}") + return cls.named_type_from_type(type, name) + + def __repr__(self): + if self.named_type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: + return "<named type: typedef %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass: + return "<named type: struct %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass: + return "<named type: union %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass: + return "<named type: enum %s>" % str(self.name) + return "<named type: unknown >" - @member_access.setter - def member_access(self, value): - core.BNTypeBuilderSetMemberAccess(self.handle, value) class Type: @@ -505,7 +1361,12 @@ class Type: def __del__(self): if core is not None: - core.BNFreeType(self._handle) + try: + core.BNFreeType(self._handle) + except: + import traceback + traceback.print_exc() + raise def __repr__(self): if self._confidence < core.max_confidence: @@ -529,12 +1390,12 @@ class Type: def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - return core.BNTypesEqual(self.handle, other.handle) + return core.BNTypesEqual(self._handle, other._handle) def __ne__(self, other): if not isinstance(other, self.__class__): return NotImplemented - return core.BNTypesNotEqual(self.handle, other.handle) + return core.BNTypesNotEqual(self._handle, other._handle) @property def handle(self): @@ -567,7 +1428,7 @@ class Type: def to_core_struct(self) -> core.BNTypeWithConfidence: type_conf = core.BNTypeWithConfidence() - type_conf.type = self.handle + type_conf.type = self._handle type_conf.confidence = self.confidence return type_conf @@ -623,7 +1484,7 @@ class Type: return result def with_confidence(self, confidence) -> 'Type': - return Type.create(handle = core.BNNewTypeReference(self.handle), platform = self._platform, confidence = confidence) + return Type.create(handle = core.BNNewTypeReference(self._handle), platform = self._platform, confidence = confidence) @property def confidence(self) -> _int: @@ -641,16 +1502,28 @@ class Type: def platform(self, value:'_platform.Platform') -> None: self._platform = value - @abstractmethod - def create_mutable(self): - raise NotImplementedError("No implementation for create_mutable on base class Type") + def mutable_copy(self) -> 'TypeBuilder': + TypeBuilders = { + TypeClass.VoidTypeClass:Void, + TypeClass.BoolTypeClass:Bool, + TypeClass.IntegerTypeClass:Integer, + TypeClass.FloatTypeClass:Float, + TypeClass.StructureTypeClass:Structure, + TypeClass.EnumerationTypeClass:Enumeration, + TypeClass.PointerTypeClass:Pointer, + TypeClass.ArrayTypeClass:Array, + TypeClass.FunctionTypeClass:Function, + TypeClass.NamedTypeReferenceClass:NamedTypeReference, + TypeClass.WideCharTypeClass:WideChar, + } + return TypeBuilders[self.type_class](core.BNCreateTypeBuilderFromType(self._handle), + self.platform, self.confidence) - def mutable_copy(self) -> 'MutableType': - return self.create_mutable() + def immutable_copy(self) -> 'Type': + return self def get_builder(self, bv:'binaryview.BinaryView') -> 'MutableTypeBuilder': - t = Types[self.type_class](self._handle).create_mutable() - return MutableTypeBuilder(t, bv, self.name, self.platform, self._confidence) + return MutableTypeBuilder(self.mutable_copy(), bv, self.name, self.platform, self._confidence) @staticmethod def builder(bv:'binaryview.BinaryView', name:Optional[QualifiedName]=None, id:Optional[str]=None, @@ -658,20 +1531,20 @@ class Type: if name is None and id is None: raise TypeCreateException("Must specify either a name or id to create a builder object") if name is None: - t = bv.get_type_by_id(id) - if t is None: + type = bv.get_type_by_id(id) + if type is None: raise TypeCreateException("failed to look up type by id") - registered_name = t.registered_name + registered_name = type.registered_name if registered_name is None: raise TypeCreateException("Registered name for type is None") name = registered_name.name if name is None: raise TypeCreateException("Name for registered name is None") else: - t = bv.get_type_by_name(name) - if t is None: + type = bv.get_type_by_name(name) + if type is None: raise TypeCreateException("failed to look up type by name") - return MutableTypeBuilder(t, bv, name, platform, confidence) + return MutableTypeBuilder(type.mutable_copy(), bv, name, platform, confidence) def with_replaced_structure(self, from_struct, to_struct): return Type.create(handle = core.BNTypeWithReplacedStructure(self._handle, from_struct.handle, to_struct.handle)) @@ -683,52 +1556,56 @@ class Type: return Type.create(handle = core.BNTypeWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) @staticmethod - def void(): + def void() -> 'VoidType': return VoidType.create() @staticmethod - def bool(): + def bool() -> 'BoolType': return BoolType.create() @staticmethod - def char(): - return Type.int(1, True) + def char(alternate_name:str="") -> 'CharType': + return CharType.create(alternate_name) @staticmethod - def int(width:_int, sign:BoolWithConfidenceType=BoolWithConfidence(True), altname:str="") -> 'IntegerType': + def int(width:_int, sign:BoolWithConfidenceType=BoolWithConfidence(True), alternate_name:str="") -> 'IntegerType': """ ``int`` class method for creating an int Type. :param int width: width of the integer in bytes :param bool sign: optional variable representing signedness - :param str altname: alternate name for type + :param str alternate_name: alternate name for type """ - return IntegerType.create(width, sign, altname) + return IntegerType.create(width, sign, alternate_name) @staticmethod - def float(width:_int, altname:str="") -> 'FloatType': + def float(width:_int, alternate_name:str="") -> 'FloatType': """ ``float`` class method for creating floating point Types. :param int width: width of the floating point number in bytes - :param str altname: alternate name for type + :param str alternate_name: alternate name for type """ - return FloatType.create(width, altname) + return FloatType.create(width, alternate_name) @staticmethod - def wide_char(width:_int, altname:str="") -> 'WideCharType': + def wide_char(width:_int, alternate_name:str="") -> 'WideCharType': """ ``wide_char`` class method for creating wide char Types. :param int width: width of the wide character in bytes - :param str altname: alternate name for type + :param str alternate_name: alternate name for type """ - return WideCharType.create(width=width, altname=altname) + return WideCharType.create(width=width, alternate_name=alternate_name) @staticmethod - def structure_type(s:'Structure'): - return s.immutable_copy() + def structure_type(structure:'Structure'): + result = structure.immutable_copy() + assert isinstance(result, NamedTypeReferenceType) + return result @staticmethod def named_type(named_type:'NamedTypeReference') -> 'NamedTypeReferenceType': - return named_type.immutable_copy() + result = named_type.immutable_copy() + assert isinstance(result, NamedTypeReferenceType) + return result @staticmethod def named_type_from_type(name:QualifiedName, type:'Type') -> 'NamedTypeReferenceType': @@ -738,7 +1615,8 @@ class Type: def named_type_from_type_and_id(type_id:str, name:QualifiedName, type:'Type') -> 'NamedTypeReferenceType': return NamedTypeReferenceType.create_from_type(name, type, type_id) - def generate_named_type_reference(self, guid:str, name:QualifiedName): + @staticmethod + def generate_named_type_reference(guid:str, name:QualifiedName) -> 'NamedTypeReferenceType': return NamedTypeReferenceType.create(NamedTypeReferenceClass.TypedefNamedTypeClass, guid, name) @staticmethod @@ -746,8 +1624,8 @@ class Type: return NamedTypeReferenceType.create_from_registered_type(view, name) @staticmethod - def enumeration_type(arch, e:'Enumeration', width:_int=None, sign:_bool=False) -> 'EnumerationType': - return EnumerationType.create(arch, e.members, e.width, e.sign) + def enumeration_type(arch, enum:'Enumeration', width:_int=None, sign:_bool=False) -> 'EnumerationType': + return EnumerationType.create(arch, enum.members, enum.width, enum.signed) @staticmethod def pointer(type:'Type', arch:'architecture.Architecture'=None, @@ -789,7 +1667,7 @@ class Type: return StructureType.create(members, packed, type) @staticmethod - def enumeration(arch:Optional['architecture.Architecture'], members:EnumMembersType=[], + def enumeration(arch:Optional['architecture.Architecture']=None, members:EnumMembersType=[], width:Optional[_int]=None, sign:BoolWithConfidenceType=BoolWithConfidence(False)) -> 'EnumerationType': return EnumerationType.create(arch, members, width, sign) @@ -820,9 +1698,6 @@ class Type: def get_auto_demangled_type_id_source() -> str: return core.BNGetAutoDemangledTypeIdSource() - def immutable_copy(self) -> 'Type': - return self - @dataclass(frozen=True) class RegisterStackAdjustmentWithConfidence: @@ -837,13 +1712,13 @@ class RegisteredNameType(Type): @property def registered_name(self) -> Optional['NamedTypeReferenceType']: """Name of type registered to binary view, if any (read-only)""" - # assert self.handle is not None, "RegisteredNameType.handle is None" + # assert self._handle is not None, "RegisteredNameType.handle is None" # assert False, f"{str(self.type_class)}" - ntr_handle = core.BNGetRegisteredTypeName(self.handle) + ntr_handle = core.BNGetRegisteredTypeName(self._handle) if ntr_handle is None: return None # assert ntr_handle is not None, "core.BNGetRegisteredTypeName returned None" - return NamedTypeReferenceType(self.handle, self.platform, self.confidence, ntr_handle) + return NamedTypeReferenceType(self._handle, self.platform, self.confidence, ntr_handle) # @property # def name(self) -> Optional[QualifiedName]: @@ -853,51 +1728,6 @@ class RegisteredNameType(Type): # return registered_name.name -@dataclass -class MutableTypeBuilder: - type:'MutableType' - container:TypeContainer - name:QualifiedName - platform:Optional['_platform.Platform'] - confidence:int - user:bool = True - - def __enter__(self): - return self.type - - def __exit__(self, type, value, traceback): - if isinstance(self.container, binaryview.BinaryView): - if self.user: - self.container.define_user_type(self.name, self.type.immutable_copy(self.platform, self.confidence)) - else: - type_id = types.Type.generate_auto_type_id(str(uuid.uuid4()), str(self.name)) - self.container.define_type(type_id, self.name, self.type.immutable_copy(self.platform, self.confidence)) - else: - self.container.add_named_type(self.name, self.type.immutable_copy()) - - -@dataclass -class MutableType(ABC): - @abstractmethod - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> Type: - return NotImplemented - - def builder(self, container:TypeContainer, name:'QualifiedName', user:bool=True, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> MutableTypeBuilder: - return MutableTypeBuilder(self, container, name, platform, confidence, user) - - @abstractmethod - def __len__(self): - return NotImplemented - - def mutable_copy(self) -> 'MutableType': - return self - -@dataclass -class CVQualified(MutableType): - const:BoolWithConfidence=BoolWithConfidence(False) - volatile:BoolWithConfidence=BoolWithConfidence(False) - - class CVQualifiedType(Type): @property def const(self): @@ -940,13 +1770,6 @@ class PointerLike(CVQualifiedType): assert result is not None, "core.BNGetChildType returned None" return Type.create(core.BNNewTypeReference(result.type), self._platform, result.confidence) -@dataclass -class Void(MutableType): - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'VoidType': - return VoidType.create(platform, confidence) - - def __len__(self): - return 0 class VoidType(Type): @classmethod @@ -955,58 +1778,6 @@ class VoidType(Type): assert core_void is not None, "core.BNCreateVoidType returned None" return cls(core.BNNewTypeReference(core_void), platform, confidence) - def create_mutable(self) -> 'Void': - return Void() - - -@dataclass -class Integer(MutableType): - width:int - altname:str="" - signed:BoolWithConfidence=BoolWithConfidence(True) - - def immutable_copy(self, **kwargs) -> 'IntegerType': - return IntegerType.create(self.width, self.signed, self.altname, **self.__dict__) - - def __len__(self): - return self.width - - -class IntegerType(CVQualifiedType): - @classmethod - def create(cls, width:int, sign:BoolWithConfidenceType=BoolWithConfidence(True), altname:str="", **kwargs) -> 'IntegerType': - if isinstance(sign, BoolWithConfidence): - _sign = sign.to_core_struct() - elif isinstance(sign, bool): - _sign = BoolWithConfidence(sign).to_core_struct() - - builder_handle = core.BNCreateIntegerTypeBuilder(width, _sign, altname, **kwargs) - assert builder_handle is not None, "core.BNCreateIntegerTypeBuilder returned None" - - handle = _TypeBuilder(builder_handle, **kwargs).finalize() - return cls(core.BNNewTypeReference(handle), **kwargs) - - def create_mutable(self) -> 'Integer': - i = Integer(self.width, self.altname, self.signed) - i.__dict__['const']__ = self.const - i.__dict__['volatile']__ = self.volatile - return i - - @property - def signed(self) -> BoolWithConfidence: - """Whether type is signed (read-only)""" - return BoolWithConfidence.from_core_struct(core.BNIsTypeSigned(self._handle)) - - -@dataclass -class Bool(MutableType): - def immutable_copy(self, platform:'_platform.Platform'=None, - confidence:int=core.max_confidence) -> 'BoolType': - return BoolType.create(platform, confidence) - - def __len__(self): - return 1 - class BoolType(Type): @classmethod @@ -1015,43 +1786,31 @@ class BoolType(Type): assert handle is not None, "core.BNCreateBoolType returned None" return cls(core.BNNewTypeReference(handle), platform, confidence) - def create_mutable(self) -> 'Bool': - return Bool() - -@dataclass -class Char(Integer): - width:int=1 - altname:str="" - sign:bool=True - - def as_char(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'CharType': - return CharType.create(self.width, self.altname, self.sign, platform, confidence) +class IntegerType(Type): + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + super(IntegerType, self).__init__(handle, platform, confidence) -class CharType(IntegerType): @classmethod - def create(cls, width:int=1, altname:str="char", sign:bool=True, - platform:'_platform.Platform'=None, confidence:int=core.max_confidence, **kwargs) -> 'CharType': - return cls(IntegerType.create(width, sign, altname, **kwargs).handle, platform, confidence) - - def create_mutable(self) -> 'Char': - return Char(self.width, self.altname, self.signed, self.const, self.volatile) + def create(cls, width:int, sign:BoolWithConfidenceType=True, alternate_name:str="", + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'IntegerType': + _sign = BoolWithConfidence.get_core_struct(sign) + handle = core.BNCreateIntegerType(width, _sign, alternate_name) + assert handle is not None, "core.BNCreateIntegerType returned None" + return cls(core.BNNewTypeReference(handle), platform, confidence) @property def signed(self) -> BoolWithConfidence: - return BoolWithConfidence(False, core.max_confidence) - + """Whether type is signed (read-only)""" + return BoolWithConfidence.from_core_struct(core.BNIsTypeSigned(self._handle)) -@dataclass -class Float(MutableType): - width:int - altname:str="" - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FloatType': - return FloatType.create(self.width, self.altname, platform, confidence) +class CharType(IntegerType): + @classmethod + def create(cls, altname:str="char", platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'CharType': + return cls(IntegerType.create(1, True, altname).handle, platform, confidence) - def __len__(self): - return self.width class FloatType(Type): @classmethod @@ -1066,30 +1825,6 @@ class FloatType(Type): assert core_float is not None, "core.BNCreateFloatType returned None" return cls(core.BNNewTypeReference(core_float), platform, confidence) - def create_mutable(self) -> 'Float': - return Float(self.width, self.altname) - - -@dataclass -class StructureMember: - type:Union[Type, MutableType] - name:str - offset:int - - def __post_init__(self): - self.type = self.type.mutable_copy() - - def __repr__(self): - # TODO: Consider showing this differently if the type is mutable - if len(self.name) == 0: - return f"<member: {self.type.immutable_copy()}, offset {self.offset:#x}>" - return f"<{self.type.immutable_copy().get_string_before_name()} {self.name}{self.type.immutable_copy().get_string_after_name()}" + \ - f", offset {self.offset:#x}>" - # return f"<StructureMember: {self.type} {self.name}>" - - def __len__(self): - return len(self.type) - class StructureType(RegisteredNameType): def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): @@ -1108,19 +1843,16 @@ class StructureType(RegisteredNameType): for member in members: if isinstance(member, Tuple): _type, _name = member - core.BNAddStructureBuilderMember(builder, _type.immutable_copy().to_core_struct(), _name) + core.BNAddStructureBuilderMember(builder, _type.immutable_copy().to_core_struct(), _name, MemberAccess.NoAccess, MemberScope.NoScope) elif isinstance(member, StructureMember): core.BNAddStructureBuilderMemberAtOffset(builder, member.type.immutable_copy().to_core_struct(), - member.name, member.offset, False) + member.name, member.offset, False, member.access, member.scope) core_struct = core.BNFinalizeStructureBuilder(builder) assert core_struct is not None, "core.BNFinalizeStructureBuilder returned None" core_type = core.BNCreateStructureType(core_struct) assert core_type is not None, "core.BNCreateStructureType returned None" return cls(core.BNNewTypeReference(core_type), platform, confidence) - def create_mutable(self) -> 'Structure': - return Structure(self.members, self.alignment, self.width, self.type, self.packed) - @classmethod def from_core_struct(cls, structure:core.BNStructure) -> 'StructureType': return cls(core.BNNewTypeReference(core.BNCreateStructureType(structure))) @@ -1136,8 +1868,8 @@ class StructureType(RegisteredNameType): def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - assert other.handle is not None - return ctypes.addressof(self.struct_handle.contents) == ctypes.addressof(other.handle.contents) + assert other._handle is not None + return ctypes.addressof(self.struct_handle.contents) == ctypes.addressof(other._handle.contents) def __ne__(self, other): if not isinstance(other, self.__class__): @@ -1223,182 +1955,12 @@ class StructureType(RegisteredNameType): self.width, self.platform, self.confidence) -@dataclass -class Structure(MutableType): - members:List[StructureMember] = field(default_factory=list) - _alignment:int=1 - _width:int=0 - type:StructureVariant=StructureVariant.StructStructureType - _packed:bool=False - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'StructureType': - return StructureType.create(self.members, self.packed, self.type, platform, confidence) - - @property - def packed(self) -> bool: - return self._packed - - @packed.setter - def packed(self, value:bool) -> None: - self._packed = value - - @property - def alignment(self) -> int: - return self._alignment - - @alignment.setter - def alignment(self, value:int) -> None: - if value == 1: - return - if value < 1: - raise ValueError("Can't set alignment to < 1") - self._alignment = value - - @property - def width(self) -> int: - return self._width - - @width.setter - def width(self, value:int) -> None: - # if greater than the current width: - # expands the structure's size - # if less than the current width: - # shrinks the structure's size removing any members which would exist outside the structure's bounds - if value < 0: - raise ValueError("Width of structure can not be negative") - - if value < self._width: - amount = self._width - (self._width - value) - self.clear_members(value, amount) - self._width = value - - def __repr__(self): - return f"<struct: size {self.width:#x}>" - - def __getitem__(self, name:str) -> Optional[StructureMember]: - for member in self.members: - if member.name == name: - return member - return None - - def __iter__(self) -> Generator[StructureMember, None, None]: - for member in self.members: - yield member - - def __len__(self) -> int: - return self._width - - def member_at_offset(self, offset:int) -> Optional[StructureMember]: - for member in self.members: - if member.offset == offset: - return member - return None - - def index_by_name(self, name:MemberName) -> Optional[MemberIndex]: - for i, member in enumerate(self.members): - if member.name == name: - return i - return None - - def index_by_offset(self, offset:MemberOffset) -> Optional[MemberIndex]: - for i, member in enumerate(self.members): - if member.offset == offset: - return i - return None - - def index_from(self, index:Optional[MemberIndex]=None, name:Optional[MemberName]=None, offset:Optional[MemberOffset]=None) -> MemberIndex: - if index is not None: - if index >= len(self.members): - raise IndexError("list index out of range") - elif name is not None: - index = self.index_by_name(name) - if index is None: - raise ValueError(f"StructureMember {name} doesn't exist") - elif offset is not None: - index = self.index_by_offset(offset) - if index is None: - raise ValueError(f"No StructureMember at offset exists") - else: - raise ValueError("One of the following must") - - return index - - def erase(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: - # removes the specified item shrinking the total size of the structure and adjusting - # the offset of any members with offsets greater than the offset of member[index]. - # In the case where there are multiple members which overlap the erased item they will be erased too - # but the structure will only be shrunken by the specified member's width - # raise exception if the index doesn't exist - # raises exception if more not exactly one of index/name/offset are not None - item = self.members[self.index_from(index, name, offset)] - self.clear_members(item.offset, len(item)) - self.adjust_space(item.offset, -len(item)) - - def clear(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: - # clears the member at the index/member-name. No adjustment is made to other members or the structure's size - # raise exception if the index doesn't exist - del self.members[self.index_from(index, name, offset)] - - def clear_members(self, offset:MemberOffset, size:int) -> None: - # clears members which overlap offset - to_clear = [] - for i, member in enumerate(self.members): - if member.offset >= offset and member.offset < offset + size: - to_clear.append(i) - elif member.offset < offset and member.offset + len(member) > offset: - to_clear.append(i) - for i in to_clear: - self.clear(index=i) - - def replace_member(self, new_name:MemberName, type:SomeType, index:MemberIndex=None, old_name:MemberName=None, offset:MemberOffset=None) -> None: - # replaces any members within the structure which overlap member[index] - index = self.index_from(index, old_name, offset) - item = self.members[index] - self.clear_members(item.offset, len(item)) - self.members.insert(index, StructureMember(type, new_name, item.offset)) - - def append(self, name:MemberName, type:SomeType) -> 'Structure': - # appends a structure at the end of the structure growing the structure - self.members.append(StructureMember(type.mutable_copy(), name, self._width)) - self._width += len(type) - return self - - def add_member_at_offset(self, name:MemberName, type:SomeType, offset:MemberOffset) -> 'Structure': - # Adds structure member to the given offset first clearing any members within the range offset-offset+len(type) - self.clear_members(offset, len(type)) - self.members.append(StructureMember(type, name, offset)) - self.members = sorted(self.members, key=lambda m: m.offset) - return self - - def adjust_space(self, offset:int, size:int) -> None: - # adds or removes undefined space at the given offset and size - # removes space and clears overlapping members if size is negative - self.members = sorted(self.members, key=lambda m: m.offset) - - if size < -self._width: - size = -self._width - - if size < 0: - self.clear_members(offset, size) - - alignment = 0 - if size % self._alignment != 0: - alignment = self._alignment - (abs(size) % self._alignment) - - new_members = [] - for member in self.members: - if member.offset > offset: - new_offset = member.offset + size + alignment - new_members.append(StructureMember(member.type, member.name, new_offset)) - self.members = new_members - self._width += size - - class EnumerationType(RegisteredNameType, IntegerType): def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): assert handle is not None, "Attempted to create EnumerationType without handle" super(EnumerationType, self).__init__(handle, platform, confidence) enum_handle = core.BNGetTypeEnumeration(handle) + core.BNNewEnumerationReference(enum_handle) assert enum_handle is not None, "core.BNGetTypeEnumeration returned None" self.enum_handle = enum_handle @@ -1428,13 +1990,12 @@ class EnumerationType(RegisteredNameType, IntegerType): core.BNAddEnumerationBuilderMemberWithValue(builder, name, value) core_enum = core.BNFinalizeEnumerationBuilder(builder) assert core_enum is not None, "core.BNFinalizeEnumerationBuilder returned None" + core.BNFreeEnumerationBuilder(builder) + core_type = core.BNCreateEnumerationTypeOfWidth(core_enum, width, sign) assert core_type is not None, "core.BNCreateEnumerationTypeOfWidth returned None" return cls(core.BNNewTypeReference(core_type), platform, confidence) - def create_mutable(self) -> 'Enumeration': - return Enumeration(self.members, len(self), self.signed) - def __del__(self): if core is not None: core.BNFreeEnumeration(self.enum_handle) @@ -1472,107 +2033,6 @@ class EnumerationType(RegisteredNameType, IntegerType): return NamedTypeReferenceType.create(ntr_type, guid, name, platform=self.platform, confidence=self.confidence) -@dataclass(frozen=True) -class EnumerationMember: - name:str - value:Optional[int] - - def __repr__(self): - value = f"{self.value:#x}" if self.value is not None else "auto()" - return f"<{self.name} = {value}>" - - -@dataclass -class Enumeration(MutableType): - members:List[EnumerationMember] = field(default_factory=list) - width:int=4 - sign:BoolWithConfidence=BoolWithConfidence(False) - - def __repr__(self): - return "<enum: %s>" % repr(self.members) - - def __len__(self): - return self.width - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'EnumerationType': - return EnumerationType.create(None, self.members, self.width, self.sign, platform, confidence) - - def append(self, name, value = None) -> 'Enumeration': - self.members.append(EnumerationMember(name, value)) - return self - - def remove(self, i): - del self.members[i] - - def replace(self, i, name, value): - self.remove(i) - self.members.insert(i, EnumerationMember(name, value)) - - def __iter__(self) -> Generator[EnumerationMember, None, None]: - for i, member in enumerate(self.members): - if member.value is None: - yield EnumerationMember(member.name, i) - else: - yield member - - def __getitem__(self, value:Union[str, int, slice]): - if isinstance(value, str) and value in self.__dict__: - return self.__dict__[value] - - if isinstance(value, str): - for member in self.members: - if member.name == value: - return member - return None - elif isinstance(value, int): - return self.members[value] - elif isinstance(value, slice): # not combined with the previous check due to pyright bug - return self.members[value] - else: - raise ValueError(f"Incompatible type {type(value)} for __getitem__") - - def __setitem__(self, item, value): - if isinstance(item, str): - for i, member in enumerate(self.members): - if member.name == item: - self.members[i] = EnumerationMember(member.name, value) - elif isinstance(item, int) and isinstance(value, EnumerationMember): - self.members[item] = value - raise ValueError(f"Incompatible type: {type(item)} for __setitem__") - - -@dataclass -class Pointer(MutableType): - _target:Optional[SomeType] = None - width:Optional[int] = None - arch:Optional['architecture.Architecture'] = None - const:BoolWithConfidenceType=BoolWithConfidence(False) - volatile:BoolWithConfidenceType=BoolWithConfidence(False) - ref_type:ReferenceType=ReferenceType.PointerReferenceType - - def __post_init__(self): - if self._target is not None: - self._target = self._target.mutable_copy() - assert self.arch is not None or self.width is not None, f"Must specify either an architecture or a width {self.arch} : {self.width}" - if self.arch is not None: - self.width = self.arch.address_size - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'PointerType': - assert self._target is not None and self.width is not None, f"Target not set for Pointer(MutableType) {self._target}, {self.width}" - return PointerType.create_with_width(self.width, self._target, self.const, self.volatile, - self.ref_type, platform, confidence) - - @property - def target(self) -> MutableType: - assert isinstance(self._target, MutableType) - return self._target - - @target.setter - def target(self, value:SomeType): # type: ignore - self._target = value.mutable_copy() - - def __len__(self): - return self.width class PointerType(PointerLike): @property @@ -1600,24 +2060,6 @@ class PointerType(PointerLike): assert core_type is not None, "core.BNCreatePointerTypeOfWidth returned None" return Type.create(core.BNNewTypeReference(core_type), platform, confidence) - def create_mutable(self) -> 'Pointer': - return Pointer(self.target, self.width, None, self.const, self.volatile, self.ref_type) - - -@dataclass -class Array(MutableType): - count:int - element_type:MutableType - - def __post_init__(self): - self.element_type = self.element_type.mutable_copy() - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'ArrayType': - return ArrayType.create(self.element_type.immutable_copy(), self.count, platform, confidence) - - def __len__(self): - return self.count * len(self.element_type) - class ArrayType(Type): @classmethod @@ -1627,9 +2069,6 @@ class ArrayType(Type): assert core_array is not None, "core.BNCreateArrayType returned None" return cls(core.BNNewTypeReference(core_array)) - def create_mutable(self) -> 'Array': - return Array(self.count, self.element_type.mutable_copy()) - @property def count(self): """Type count (read-only)""" @@ -1641,45 +2080,6 @@ class ArrayType(Type): assert result is not None, "core.BNGetChildType returned None" return Type.create(core.BNNewTypeReference(result.type), self._platform, result.confidence) - -@dataclass -class Function(MutableType): - _return_type:Optional[SomeType] = None - parameters:List[FunctionParameter] = field(default_factory=list) - calling_convention:Optional['callingconvention.CallingConvention'] = None - variable_arguments:BoolWithConfidenceType = BoolWithConfidence(False) - stack_adjustment:OffsetWithConfidence = OffsetWithConfidence(0) - - def __post_init__(self): - if self._return_type is not None: - self._return_type = self._return_type.mutable_copy() - if len(self.parameters) > 0: - self.parameters = [param.mutable_copy() for param in self.parameters] - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FunctionType': - immutable_parameters = [param.immutable_copy() for param in self.parameters] - if self._return_type is None: - self._return_type = Type.void() - return FunctionType.create(self._return_type.immutable_copy(), immutable_parameters, self.calling_convention, - self.variable_arguments, self.stack_adjustment, platform, confidence) - - @property - def return_type(self): - return self._return_type - - @return_type.setter - def return_type(self, value:SomeType): - self._return_type = value.mutable_copy() - - def append(self, type:Union[SomeType, FunctionParameter], name:str=""): - if isinstance(type, FunctionParameter): - self.parameters.append(type.mutable_copy()) - else: - self.parameters.append(FunctionParameter(type.mutable_copy(), name)) - - def __len__(self): - return 0 - class FunctionType(Type): @classmethod def create(cls, ret:Optional[Type]=None, params:ParamsType=[], @@ -1746,9 +2146,6 @@ class FunctionType(Type): _variable_arguments.to_core_struct(), _stack_adjust.to_core_struct()) return cls(core.BNNewTypeReference(func_type), platform, confidence) - def create_mutable(self) -> 'Function': - return Function(self.return_value.mutable_copy(), self.parameters, self.calling_convention, self.has_variable_arguments, self.stack_adjustment) - @property def stack_adjustment(self) -> OffsetWithConfidence: """Stack adjustment for function (read-only)""" @@ -1807,41 +2204,6 @@ class FunctionType(Type): return BoolWithConfidence(result.value, confidence = result.confidence) -# @dataclass -# class Value(MutableType): -# pass - - -# class ValueType(Type): -# pass - - -@dataclass -class NamedTypeReference(MutableType): - name:QualifiedName - id:str - named_type_class:NamedTypeReferenceClass=NamedTypeReferenceClass.UnknownNamedTypeClass - alignment:int = 0 - width:int = 0 - - def __repr__(self): - if self.named_type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: - return "<named type: typedef %s>" % str(self.name) - if self.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass: - return "<named type: struct %s>" % str(self.name) - if self.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass: - return "<named type: union %s>" % str(self.name) - if self.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass: - return "<named type: enum %s>" % str(self.name) - return "<named type: unknown >" - - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'NamedTypeReferenceType': - return NamedTypeReferenceType.create(self.named_type_class, self.id, self.name, self.alignment, self.width, - platform, confidence) - - def __len__(self): - return self.width - class NamedTypeReferenceType(RegisteredNameType): def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence, ntr_handle=None): assert handle is not None, "Attempting to create NamedTypeReferenceType handle which is None" @@ -1886,9 +2248,6 @@ class NamedTypeReferenceType(RegisteredNameType): assert core_type is not None, "core.BNCreateNamedTypeReferenceFromType returned None" return cls(core.BNNewTypeReference(core_type), platform, confidence) - def create_mutable(self) -> 'NamedTypeReference': - return NamedTypeReference(self.name, self.type_id, self.named_type_class, self.alignment, self.width) - def __del__(self): if core is not None: core.BNFreeNamedTypeReference(self.ntr_handle) @@ -1915,8 +2274,8 @@ class NamedTypeReferenceType(RegisteredNameType): def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - assert other.handle is not None - return ctypes.addressof(self.ntr_handle.contents) == ctypes.addressof(other.handle.contents) + assert other._handle is not None + return ctypes.addressof(self.ntr_handle.contents) == ctypes.addressof(other._handle.contents) def __ne__(self, other): if not isinstance(other, self.__class__): @@ -1966,22 +2325,17 @@ class NamedTypeReferenceType(RegisteredNameType): # return cls(core_type, platform, confidence) -@dataclass -class WideChar(Integer): - def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'WideCharType': - return WideCharType.create(self.width, self.altname, platform, confidence) - - class WideCharType(Type): @classmethod - def create(cls, width:int, altname:str="", platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'WideCharType': + def create(cls, width:int, alternate_name:str="", platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'WideCharType': """ ``wide_char`` class method for creating wide char Types. :param int width: width of the wide character in bytes - :param str altname: alternate name for type + :param str alternate_name: alternate name for type """ - core_type = core.BNCreateWideCharType(width, altname) + core_type = core.BNCreateWideCharType(width, alternate_name) assert core_type is not None, "core.BNCreateWideCharType returned None" return cls(core.BNNewTypeReference(core_type), platform, confidence) @@ -1999,21 +2353,6 @@ Types = { TypeClass.WideCharTypeClass:WideCharType, } -MutableTypes = { - TypeClass.VoidTypeClass:Void, - TypeClass.BoolTypeClass:Bool, - TypeClass.IntegerTypeClass:Integer, - TypeClass.FloatTypeClass:Float, - TypeClass.StructureTypeClass:Structure, - TypeClass.EnumerationTypeClass:Enumeration, - TypeClass.PointerTypeClass:Pointer, - TypeClass.ArrayTypeClass:Array, - TypeClass.FunctionTypeClass:Function, - TypeClass.NamedTypeReferenceClass:NamedTypeReference, - TypeClass.WideCharTypeClass:WideChar, -} - - @dataclass(frozen=True) class RegisterSet: regs:List['architecture.RegisterName'] @@ -2033,9 +2372,6 @@ class RegisterSet: return RegisterSet(list(self.regs), confidence=confidence) - - - @dataclass(frozen=True) class TypeParserResult: types:Mapping[QualifiedName, Type] diff --git a/python/variable.py b/python/variable.py index 1ed38c2d..d5e318c2 100644 --- a/python/variable.py +++ b/python/variable.py @@ -812,8 +812,8 @@ class ParameterVariables: @dataclass(frozen=True, order=True) class AddressRange: - start:int - end:int + start:int # Inclusive starting address + end:int # Exclusive ending address def __repr__(self): return f"<{self.start:#x}-{self.end:#x}>"
\ No newline at end of file diff --git a/suite/testcommon.py b/suite/testcommon.py index 71f97c05..f5448e0a 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -687,17 +687,17 @@ class TestBuilder(Builder): """Struct produced different result""" retinfo = [] inttype = binja.Type.int(4) - struct = binja.Structure() - struct.append("", inttype) - struct.append("", inttype) - struct.replace_member(new_name="", type=inttype, offset=0) - struct.clear(index=1) + struct = binja.TypeBuilder.structure() + struct.insert(0, inttype) + struct.append(inttype) + struct.replace(0, inttype) + struct.remove(1) for i in struct.members: retinfo.append("Struct member: " + str(i)) retinfo.append("Struct width: " + str(struct.width)) struct.width = 16 retinfo.append("Struct width after adjustment: " + str(struct.width)) - retinfo.append("Struct alignment: " + str(struct.alignment * 4)) # TODO Remove when regenerating this + retinfo.append("Struct alignment: " + str(struct.alignment)) struct.alignment = 8 retinfo.append("Struct alignment after adjustment: " + str(struct.alignment)) retinfo.append("Struct packed: " + str(struct.packed)) @@ -712,7 +712,7 @@ class TestBuilder(Builder): def test_Enumeration(self): """Enumeration produced different result""" retinfo = [] - enum = binja.Enumeration() + enum = binja.TypeBuilder.enumeration() enum.append("a", 1) enum.append("b", 2) enum.replace(0, "a", 2) @@ -740,7 +740,7 @@ class TestBuilder(Builder): typelist = bv.platform.parse_types_from_source(source) inttype = binja.Type.int(4) - namedtype = binja.NamedTypeReference(None, None) # TODO: Change this as it really doesn't do anything + namedtype = binja.NamedTypeReference("", "") # TODO: Change this as it really doesn't do anything tokens = inttype.get_tokens() + inttype.get_tokens_before_name() + inttype.get_tokens_after_name() retinfo = [] for i in range(len(typelist.variables)): @@ -1787,12 +1787,10 @@ class VerifyBuilder(Builder): try: with binja.open_view(file_name) as bv: # struct A { uint64_t a; uint64_t b; }; - s = binja.Structure() - s.width = 0x10 - s.append("a", binja.Type.int(8, False)) - s.append("b", binja.Type.int(8, False)) - t = binja.Type.structure_type(s) - bv.define_user_type("A", t) + with binja.Structure.builder(bv, "A") as s: + s.width = 0x10 + s.append(binja.Type.int(8, False), "a") + s.append(binja.Type.int(8, False), "b") # Find main and the var it sets to malloc(0x10) func = [f for f in bv.functions if f.name == '_main'][0] |
