diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 257 | ||||
| -rw-r--r-- | python/basicblock.py | 79 | ||||
| -rw-r--r-- | python/lowlevelil.py | 427 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 49 | ||||
| -rw-r--r-- | python/types.py | 435 | ||||
| -rw-r--r-- | python/variable.py | 228 |
6 files changed, 326 insertions, 1149 deletions
diff --git a/python/architecture.py b/python/architecture.py index 7dd8ff91..2d6fde0f 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -21,6 +21,7 @@ import traceback import ctypes from typing import Generator, Union, List, Optional, Mapping, Tuple, NewType +from dataclasses import dataclass # Binary Ninja components import binaryninja @@ -61,258 +62,86 @@ SemanticGroupType = Union[SemanticGroupName, 'lowlevelil.ILSemanticFlagGroup', S IntrinsicType = Union[IntrinsicName, 'lowlevelil.ILIntrinsic', IntrinsicIndex] - +@dataclass(frozen=False) class RegisterInfo(object): - def __init__(self, full_width_reg:RegisterName, size:int, offset:int=0, - extend:ImplicitRegisterExtend=ImplicitRegisterExtend.NoExtend, index:RegisterIndex=None): - self._full_width_reg = full_width_reg - self._offset = offset - self._size = size - self._extend = extend - self._index = index + full_width_reg:RegisterName + offset:int + size:int = 0 + extend:ImplicitRegisterExtend = ImplicitRegisterExtend.NoExtend + index:Optional[RegisterIndex] = None def __repr__(self): - if self._extend == ImplicitRegisterExtend.ZeroExtendToFullWidth: + if self.extend == ImplicitRegisterExtend.ZeroExtendToFullWidth: extend = ", zero extend" - elif self._extend == ImplicitRegisterExtend.SignExtendToFullWidth: + elif self.extend == ImplicitRegisterExtend.SignExtendToFullWidth: extend = ", sign extend" else: extend = "" - return "<reg: size %d, offset %d in %s%s>" % (self._size, self._offset, self._full_width_reg, extend) - - @property - def full_width_reg(self) -> RegisterName: - return self._full_width_reg - - @full_width_reg.setter - def full_width_reg(self, value:RegisterName) -> None: - self._full_width_reg = value - - @property - def offset(self) -> int: - return self._offset - - @offset.setter - def offset(self, value:int) -> None: - self._offset = value - - @property - def size(self) -> int: - return self._size - - @size.setter - def size(self, value:int) -> None: - self._size = value - - @property - def extend(self) -> ImplicitRegisterExtend: - return self._extend - - @extend.setter - def extend(self, value:ImplicitRegisterExtend) -> None: - self._extend = value - - @property - def index(self) -> Optional[RegisterIndex]: - return self._index - - @index.setter - def index(self, value:RegisterIndex) -> None: - self._index = value + return "<reg: size %d, offset %d in %s%s>" % (self.size, self.offset, self.full_width_reg, extend) +@dataclass(frozen=False) class RegisterStackInfo(object): - def __init__(self, storage_regs:List[RegisterName], top_relative_regs:List[RegisterName], - stack_top_reg:RegisterName, index:RegisterStackIndex=None): - self._storage_regs = storage_regs - self._top_relative_regs = top_relative_regs - self._stack_top_reg = stack_top_reg - self._index = index + storage_regs:List[RegisterName] + top_relative_regs:List[RegisterName] + stack_top_reg:RegisterName + index:Optional[RegisterStackIndex] = None def __repr__(self): - return "<reg stack: %d regs, stack top in %s>" % (len(self._storage_regs), self._stack_top_reg) - - @property - def storage_regs(self) -> List[RegisterName]: - return self._storage_regs - - @storage_regs.setter - def storage_regs(self, value:List[RegisterName]) -> None: - self._storage_regs = value - - @property - def top_relative_regs(self) -> List[RegisterName]: - return self._top_relative_regs - - @top_relative_regs.setter - def top_relative_regs(self, value:List[RegisterName]) -> None: - self._top_relative_regs = value - - @property - def stack_top_reg(self) -> RegisterName: - return self._stack_top_reg - - @stack_top_reg.setter - def stack_top_reg(self, value:RegisterName) -> None: - self._stack_top_reg = value - - @property - def index(self) -> Optional[RegisterStackIndex]: - return self._index - - @index.setter - def index(self, value:RegisterStackIndex) -> None: - self._index = value + return "<reg stack: %d regs, stack top in %s>" % (len(self.storage_regs), self.stack_top_reg) +@dataclass(frozen=True) class IntrinsicInput(object): - def __init__(self, type_obj, name=""): - self._name = name - self._type = type_obj + type:'types.Type' + name:str = "" def __repr__(self): - if len(self._name) == 0: - return "<input: %s>" % str(self._type) - return "<input: %s %s>" % (str(self._type), self._name) - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value - - @property - def type(self): - return self._type - - @type.setter - def type(self, value): - self._type = value + if len(self.name) == 0: + return "<input: %s>" % str(self.type) + return "<input: %s %s>" % (str(self.type), self.name) +@dataclass(frozen=True) class IntrinsicInfo(object): - def __init__(self, inputs, outputs, index=None): - self._inputs = inputs - self._outputs = outputs - self._index = index + inputs:List[IntrinsicInput] + outputs:List['types.Type'] + index:Optional[int] = None def __repr__(self): - return "<intrinsic: %s -> %s>" % (repr(self._inputs), repr(self._outputs)) - - @property - def inputs(self): - return self._inputs - - @inputs.setter - def inputs(self, value): - self._inputs = value - - @property - def outputs(self): - return self._outputs - - @outputs.setter - def outputs(self, value): - self._outputs = value - - @property - def index(self): - return self._index - - @index.setter - def index(self, value): - self._index = value + return f"<intrinsic: {repr(self.inputs)} -> {repr(self.outputs)}>" +@dataclass(frozen=True) class InstructionBranch(object): - def __init__(self, branch_type, target = 0, arch = None): - self._type = branch_type - self._target = target - self._arch = arch + type:BranchType + target:int + arch:'Architecture' def __repr__(self): - branch_type = self._type - if self._arch is not None: - return "<%s: %s@%#x>" % (branch_type.name, self._arch.name, self._target) - return "<%s: %#x>" % (branch_type, self._target) - - @property - def type(self): - return self._type - - @type.setter - def type(self, value): - self._type = value - - @property - def target(self): - return self._target - - @target.setter - def target(self, value): - self._target = value - - @property - def arch(self): - return self._arch - - @arch.setter - def arch(self, value): - self._arch = value + if self.arch is not None: + return f"<{self.type.name}: {self.arch.name}@{self.target:#x}>" + return f"<{self.type}: {self.target:#x}>" +@dataclass(frozen=False) class InstructionInfo(object): - def __init__(self): - self.length = 0 - self.arch_transition_by_target_addr = False - self.branch_delay = False - self.branches = [] + length:int = 0 + arch_transition_by_target_addr:bool = False + branch_delay:bool = False + branches:List[InstructionBranch] = [] def add_branch(self, branch_type, target = 0, arch = None): - self._branches.append(InstructionBranch(branch_type, target, arch)) + self.branches.append(InstructionBranch(branch_type, target, arch)) def __len__(self): - return self._length + return self.length def __repr__(self): branch_delay = "" - if self._branch_delay: + if self.branch_delay: branch_delay = ", delay slot" - return "<instr: %d bytes%s, %s>" % (self._length, branch_delay, repr(self._branches)) - - @property - def length(self): - return self._length - - @length.setter - def length(self, value): - self._length = value - - @property - def arch_transition_by_target_addr(self): - return self._arch_transition_by_target_addr - - @arch_transition_by_target_addr.setter - def arch_transition_by_target_addr(self, value): - self._arch_transition_by_target_addr = value - - @property - def branch_delay(self): - return self._branch_delay - - @branch_delay.setter - def branch_delay(self, value): - self._branch_delay = value - - @property - def branches(self): - return self._branches - - @branches.setter - def branches(self, value): - self._branches = value + return f"<instr: {self.length} bytes{branch_delay}, {repr(self.branches)}>" class _ArchitectureMetaClass(type): diff --git a/python/basicblock.py b/python/basicblock.py index 1bc29167..fa360a53 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -19,6 +19,7 @@ # IN THE SOFTWARE. import ctypes +from dataclasses import dataclass from typing import Generator, Optional, List, Tuple # Binary Ninja components @@ -30,75 +31,21 @@ from .enums import BranchType, HighlightStandardColor # from . import binaryview # from . import architecture -class BasicBlockEdge(object): - def __init__(self, branch_type:BranchType, source:'BasicBlock', target:'BasicBlock', back_edge:bool, fall_through:bool): - self._type = branch_type - self._source = source - self._target = target - self._back_edge = back_edge - self._fall_through = fall_through +@dataclass +class BasicBlockEdge: + type:BranchType + source:'BasicBlock' + target:'BasicBlock' + back_edge:bool + fall_through:bool def __repr__(self): - if self._type == BranchType.UnresolvedBranch: - return "<%s>" % BranchType(self._type).name - elif self._target.arch: - return "<%s: %s@%#x>" % (BranchType(self._type).name, self._target.arch.name, self._target.start) + if self.type == BranchType.UnresolvedBranch: + return f"<{self.type.name}>" + elif self.target.arch: + return f"<{self.type.name}: {self.target.arch.name}@{self.target.start:#x}>" else: - return "<%s: %#x>" % (BranchType(self._type).name, self._target.start) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._type, self._source, self._target, self._back_edge, self._fall_through) == \ - (other._type, other._source, other._target, other._back_edge, other._fall_through) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._type, self._source, self._target, self.back_edge, self.fall_through)) - - @property - def type(self) -> BranchType: - return self._type - - @type.setter - def type(self, value:BranchType) -> None: - self._type = value - - @property - def source(self) -> 'BasicBlock': - return self._source - - @source.setter - def source(self, value:'BasicBlock') -> None: - self._source = value - - @property - def target(self) -> 'BasicBlock': - return self._target - - @target.setter - def target(self, value:'BasicBlock') -> None: - self._target = value - - @property - def back_edge(self) -> bool: - return self._back_edge - - @back_edge.setter - def back_edge(self, value:bool) -> None: - self._back_edge = value - - @property - def fall_through(self) -> bool: - return self._fall_through - - @fall_through.setter - def fall_through(self, value:bool) -> None: - self._fall_through = value + return f"<{self.type.name}: {self.target.start:#x}>" diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 483f88e5..55da5993 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -22,6 +22,7 @@ import ctypes from enum import Flag import struct from typing import Generator, List, Optional, Any, Mapping, Union, Tuple, NewType +from dataclasses import dataclass # Binary Ninja components from .enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType, DataFlowQueryOption, FunctionGraphType @@ -45,6 +46,7 @@ ILRegisterType = Union[str, 'ILRegister', int] LLILInstructionsType = Generator['LowLevelILInstruction', None, None] LLILBasicBlocksType = Generator['LowLevelILBasicBlock', None, None] + class LowLevelILLabel(object): def __init__(self, handle:core.BNLowLevelILLabel=None): if handle is None: @@ -53,434 +55,203 @@ class LowLevelILLabel(object): else: self.handle = handle - -# TODO : It would be nice to add a `.versions` to IL vars (regs, stack regs, flags) to see all the SSA versions of the given variable. Would need to associate the source function +@dataclass(frozen=True) class ILRegister(object): - def __init__(self, arch:'architecture.Architecture', reg:'architecture.RegisterIndex'): - self._arch = arch - self._index = reg - self._temp = (self._index & 0x80000000) != 0 - if self._temp: - self._name = architecture.RegisterName("temp%d" % (self._index & 0x7fffffff)) - else: - self._name = architecture.RegisterName(self._arch.get_reg_name(self._index)) - - @property - def info(self) -> 'architecture.RegisterInfo': - return self._arch.regs[self._name] + arch:'architecture.Architecture' + index:'architecture.RegisterIndex' def __repr__(self): - return f"<reg {self._name}>" + return f"<reg {self.name}>" def __str__(self): - return self._name + return self.name + + def __int__(self): + return self.index def __eq__(self, other): - if isinstance(other, architecture.RegisterName) and other in self._arch.regs: - index = self._arch.regs[other].index + if isinstance(other, architecture.RegisterName) and other in self.arch.regs: + index = self.arch.regs[other].index assert index is not None - other = ILRegister(self._arch, index) + other = ILRegister(self.arch, index) elif not isinstance(other, self.__class__): return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, (self.__class__, str)): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) - - @property - def arch(self) -> 'architecture.Architecture': - return self._arch + return (self.arch, self.index) == (other.arch, other.index) @property - def index(self) -> 'architecture.RegisterIndex': - return self._index + def info(self) -> 'architecture.RegisterInfo': + return self.arch.regs[self.name] @property def temp(self) -> bool: - return self._temp + return (self.index & 0x80000000) != 0 @property - def name(self) -> str: - return self._name + def name(self) -> architecture.RegisterName: + if self.temp: + return architecture.RegisterName(f"temp{self.index & 0x7fffffff}") + else: + return architecture.RegisterName(self.arch.get_reg_name(self.index)) +@dataclass(frozen=True) class ILRegisterStack(object): - def __init__(self, arch:'architecture.Architecture', reg_stack:'architecture.RegisterStackIndex'): - self._arch = arch - self._index = reg_stack - self._name = self._arch.get_reg_stack_name(self._index) - - @property - def info(self): - return self._arch.reg_stacks[self._name] + arch:'architecture.Architecture' + index:'architecture.RegisterStackIndex' def __repr__(self): - return f"<reg-stack {self._name}>" + return f"<reg-stack {self.name}>" def __str__(self): - return self._name + return self.name - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) - - @property - def arch(self) -> 'architecture.Architecture': - return self._arch + def __int__(self): + return self.index @property - def index(self) -> 'architecture.RegisterStackIndex': - return self._index + def info(self) -> 'architecture.RegisterStackInfo': + return self.arch.reg_stacks[self.name] @property - def name(self) -> str: - return self._name + def name(self) -> 'architecture.RegisterStackName': + return self.arch.get_reg_stack_name(self.index) +@dataclass(frozen=True) class ILFlag(object): - def __init__(self, arch:'architecture.Architecture', flag:'architecture.FlagIndex'): - self._arch = arch - self._index = flag - self._temp = (self._index & 0x80000000) != 0 - if self._temp: - self._name = "cond:%d" % (self._index & 0x7fffffff) - else: - self._name = self._arch.get_flag_name(self._index) + arch:'architecture.Architecture' + index:'architecture.FlagIndex' def __repr__(self): - return f"<flag {self._name}>" + return f"<flag {self.name}>" def __str__(self): - return self._name - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) + return self.name def __int__(self): - return self._index - - @property - def arch(self) -> 'architecture.Architecture': - return self._arch - - @property - def index(self) -> 'architecture.FlagIndex': - return self._index + return self.index @property def temp(self): - return self._temp + return (self.index & 0x80000000) != 0 @property - def name(self) -> str: - return self._name + def name(self) -> 'architecture.FlagName': + if self.temp: + return architecture.FlagName(f"cond:{(self.index & 0x7fffffff)}") + else: + return architecture.FlagName(self.arch.get_flag_name(self.index)) +@dataclass(frozen=True) class ILSemanticFlagClass(object): - def __init__(self, arch:'architecture.Architecture', sem_class:'architecture.SemanticClassIndex'): - self._arch = arch - self._index = sem_class - self._name = self._arch.get_semantic_flag_class_name(self._index) + arch:'architecture.Architecture' + index:'architecture.SemanticClassIndex' def __repr__(self): - return self._name + return self.name def __str__(self): - return self._name - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) - - @property - def arch(self) -> 'architecture.Architecture': - return self._arch + return self.name - @property - def index(self) -> 'architecture.SemanticClassIndex': - return self._index + def __int__(self): + return self.index @property - def name(self) -> str: - return self._name + def name(self) -> 'architecture.SemanticClassName': + return self.arch.get_semantic_flag_class_name(self.index) +@dataclass(frozen=True) class ILSemanticFlagGroup(object): - def __init__(self, arch:'architecture.Architecture', sem_group:'architecture.SemanticGroupIndex'): - self._arch = arch - self._index = sem_group - self._name = self._arch.get_semantic_flag_group_name(self._index) + arch:'architecture.Architecture' + index:'architecture.SemanticGroupIndex' def __repr__(self): - return self._name + return self.name def __str__(self): - return self._name - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) - - @property - def arch(self) -> 'architecture.Architecture': - return self._arch + return self.name - @property - def index(self) -> 'architecture.SemanticGroupIndex': - return self._index + def __int__(self): + return self.index @property def name(self) -> 'architecture.SemanticGroupName': - return self._name + return self.arch.get_semantic_flag_group_name(self.index) +@dataclass(frozen=True) class ILIntrinsic(object): - def __init__(self, arch:'architecture.Architecture', intrinsic:'architecture.IntrinsicIndex'): - self._arch = arch - self._index = intrinsic - self._name = self._arch.get_intrinsic_name(self._index) - if self._name in self._arch.intrinsics: - self._inputs = self._arch.intrinsics[self._name].inputs - self._outputs = self._arch.intrinsics[self._name].outputs + arch:'architecture.Architecture' + index:'architecture.IntrinsicIndex' def __repr__(self): - return self._name + return self.name def __str__(self): - return self._name - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._arch, self._index, self._name) == (other._arch, other._index, other._name) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._arch, self._index, self._name)) + return self.name @property - def arch(self) -> 'architecture.Architecture': - return self._arch - - @property - def index(self) -> 'architecture.IntrinsicIndex': - return self._index - - @property - def name(self) -> str: - return self._name + def name(self) -> 'architecture.IntrinsicName': + return self.arch.get_intrinsic_name(self.index) @property def inputs(self) -> List['architecture.IntrinsicInput']: """``inputs`` is only available if the IL intrinsic is an Architecture intrinsic """ - return self._inputs + return self.arch.intrinsics[self.name].inputs @property def outputs(self) -> List['types.Type']: """``outputs`` is only available if the IL intrinsic is an Architecture intrinsic """ - return self._outputs + return self.arch.intrinsics[self.name].outputs +@dataclass(frozen=True) class SSARegister(object): - def __init__(self, reg:ILRegister, version:int): - self._reg = reg - self._version = version + reg:ILRegister + version:int def __repr__(self): - return "<ssa %s version %d>" % (repr(self._reg), self._version) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._reg, self._version) == (other._reg, other._version) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._reg, self._version)) - - @property - def reg(self) -> ILRegister: - return self._reg - - @property - def version(self) -> int: - return self._version - - @version.setter - def version(self, value): - self._version = value + return f"<ssa {self.reg} version {self.version}>" +@dataclass(frozen=True) class SSARegisterStack(object): - def __init__(self, reg_stack:ILRegisterStack, version:int): - self._reg_stack = reg_stack - self._version = version + reg_stack:ILRegisterStack + version:int def __repr__(self): - return "<ssa %s version %d>" % (repr(self._reg_stack), self._version) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._reg_stack, self._version) == (other._reg_stack, other._version) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._reg_stack, self._version)) - - @property - def reg_stack(self) -> ILRegisterStack: - return self._reg_stack - - @property - def version(self) -> int: - return self._version + return f"<ssa {self.reg_stack} version {self.version}>" +@dataclass(frozen=True) class SSAFlag(object): - def __init__(self, flag:ILFlag, version:int): - self._flag = flag - self._version = version + flag:ILFlag + version:int def __repr__(self): - return "<ssa %s version %d>" % (repr(self._flag), self._version) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._flag, self._version) == (other._flag, other._version) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._flag, self._version)) - - @property - def flag(self) -> ILFlag: - return self._flag - - @property - def version(self) -> int: - return self._version + return f"<ssa {self.flag} version {self.version}>" +@dataclass(frozen=True) class SSARegisterOrFlag(object): - def __init__(self, reg_or_flag:Union[ILRegister, ILFlag], version:int): - self._reg_or_flag = reg_or_flag - self._version = version + reg_or_flag:Union[ILRegister, ILFlag] + version:int def __repr__(self): - return "<ssa %s version %d>" % (repr(self._reg_or_flag), self._version) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._reg_or_flag == other._reg_or_flag) and (self._version == other._version) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._reg_or_flag, self._version)) - - @property - def reg_or_flag(self) -> Union[ILRegister, ILFlag]: - return self._reg_or_flag - - @property - def version(self) -> int: - return self._version + return f"<ssa {self.reg_or_flag} version {self.version}>" +@dataclass(frozen=True) class LowLevelILOperationAndSize(object): - def __init__(self, operation:'LowLevelILOperation', size:int): - self._operation = operation - self._size = size + operation:'LowLevelILOperation' + size:int def __repr__(self): - if self._size == 0: - return "<%s>" % self._operation.name - return "<%s %d>" % (self._operation.name, self._size) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._operation, self._size) == (other._operation, other._size) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._operation, self._size)) - - @property - def operation(self) -> 'LowLevelILOperation': - return self._operation - - @property - def size(self) -> int: - return self._size + if self.size == 0: + return f"<{self.operation.name}>" + return "<{self.operation.name} {self.size}>" class LowLevelILInstruction(object): @@ -876,7 +647,7 @@ class LowLevelILInstruction(object): """IL basic block object containing this expression (read-only) (only available on finalized functions)""" assert self._function.source_function is not None view = self._function.source_function.view - core_block = core.BNGetLowLevelILBasicBlockForInstruction(self._function.handle, self._instr_index) + core_block = core.BNGetLowLevelILBasicBlockForInstruction(self._function.handle, self._insstr_index) assert core_block is not None, "BNGetLowLevelILBasicBlockForInstruction returned None" return LowLevelILBasicBlock(view, core_block, self._function) @@ -1161,6 +932,7 @@ class LowLevelILInstruction(object): return self._operands +@dataclass(frozen=True) class LowLevelILExpr(object): """ ``class LowLevelILExpr`` hold the index of IL Expressions. @@ -1168,15 +940,10 @@ class LowLevelILExpr(object): .. note:: This class shouldn't be instantiated directly. Rather the helper members of LowLevelILFunction should be \ used instead. """ - def __init__(self, index:ExpressionIndex): - self._index = index + index:ExpressionIndex def __int__(self) -> int: - return self._index - - @property - def index(self): - return self._index + return self.index class LowLevelILFunction(object): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 61cc420f..fdc4c2e9 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -1265,6 +1265,55 @@ class MediumLevelILFunction(object): def source_function(self) -> 'function.Function': return self._source_function + @source_function.setter + def source_function(self, value): + self._source_function = value + + @property + def il_form(self) -> "binaryninja.enums.FunctionGraphType": + if len(self.basic_blocks) < 1: + return FunctionGraphType.InvalidILViewType + return FunctionGraphType(core.BNGetBasicBlockFunctionGraphType(self.basic_blocks[0].handle)) + + @property + def vars(self) -> List["binaryninja.function.Variable"]: + """This gets just the MLIL variables - you may be interested in the union of `MediumLevelIlFunction.source_function.param_vars` for all the variables used in the function""" + if self.source_function is None: + return [] + + if self.il_form in [FunctionGraphType.MediumLevelILFunctionGraph, FunctionGraphType.MediumLevelILSSAFormFunctionGraph, FunctionGraphType.MappedMediumLevelILFunctionGraph, FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph]: + count = ctypes.c_ulonglong() + core_variables = core.BNGetMediumLevelILVariables(self.handle, count) + result = [] + for var_i in range(count.value): + result.append(function.Variable(self.source_function, core_variables[var_i].type, core_variables[var_i].index, core_variables[var_i].storage)) + core.BNFreeVariableList(core_variables) + return result + return [] + + @property + def ssa_vars(self) -> List["binaryninja.mediumlevelil.SSAVariable"]: + """This gets just the MLIL SSA variables - you may be interested in the union of `MediumLevelIlFunction.source_function.param_vars` for all the variables used in the function""" + if self.source_function is None: + return [] + + if self.il_form in [FunctionGraphType.MediumLevelILSSAFormFunctionGraph, FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph]: + variable_count = ctypes.c_ulonglong() + core_variables = core.BNGetMediumLevelILVariables(self.handle, variable_count) + result = [] + for var_i in range(variable_count.value): + version_count = ctypes.c_ulonglong() + versions = core.BNGetMediumLevelILVariableSSAVersions(self.handle, core_variables[var_i], version_count) + + for version_i in range(version_count.value): + result.append(SSAVariable(function.Variable(self.source_function, core_variables[var_i].type, core_variables[var_i].index, core_variables[var_i].storage), versions[version_i])) + core.BNFreeILInstructionList(versions) + + core.BNFreeVariableList(core_variables) + return result + + return [] + class MediumLevelILBasicBlock(basicblock.BasicBlock): def __init__(self, handle:core.BNBasicBlock, owner:MediumLevelILFunction, view:Optional['binaryview.BinaryView']=None): diff --git a/python/types.py b/python/types.py index 87fa7ddb..a44be854 100644 --- a/python/types.py +++ b/python/types.py @@ -218,6 +218,7 @@ class TypeReferenceSource(object): def __hash__(self): return hash(str(self)) + class NameSpace(QualifiedName): def __str__(self): return ":".join(self.name) @@ -346,41 +347,16 @@ class Symbol(object): def auto(self): return core.BNIsSymbolAutoDefined(self.handle) - +@dataclass(frozen=True) class FunctionParameter(object): - def __init__(self, param_type, name = "", location = None): - self._type = param_type - self._name = name - self._location = location + type:'types.Type' + name:str = "" + location:Optional['variable.VariableNameAndType'] = None def __repr__(self): - if (self._location is not None) and (self._location.name != self._name): - return "%s %s%s @ %s" % (self._type.get_string_before_name(), self._name, self._type.get_string_after_name(), self._location.name) - return "%s %s%s" % (self._type.get_string_before_name(), self._name, self._type.get_string_after_name()) - - @property - def type(self): - return self._type - - @type.setter - def type(self, value): - self._type = value - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value - - @property - def location(self): - return self._location - - @location.setter - def location(self, value): - self._location = value + if (self.location is not None) and (self.location.name != self.name): + return "%s %s%s @ %s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name(), self.location.name) + return "%s %s%s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name()) class Type(object): @@ -997,166 +973,50 @@ class Type(object): return Type(handle = core.BNTypeWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) +@dataclass(frozen=True) class BoolWithConfidence(object): - def __init__(self, value, confidence = core.max_confidence): - self._value = value - self._confidence = confidence - - def __str__(self): - return str(self._value) - - def __repr__(self): - return repr(self._value) + value:bool + confidence:int=core.max_confidence def __bool__(self): - return self._value - - def __nonzero__(self): - return self._value - - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = value - - @property - def confidence(self): - return self._confidence - - @confidence.setter - def confidence(self, value): - self._confidence = value + return self.value +@dataclass(frozen=True) class SizeWithConfidence(object): - def __init__(self, value:int, confidence:int=core.max_confidence): - self._value = value - self._confidence = confidence - - def __str__(self): - return str(self._value) - - def __repr__(self): - return repr(self._value) + value:int + confidence:int=core.max_confidence def __int__(self): - return self._value - - @property - def value(self) -> int: - return self._value - - @value.setter - def value(self, value:int) -> None: - self._value = value - - @property - def confidence(self) -> int: - return self._confidence - - @confidence.setter - def confidence(self, value:int) -> None: - self._confidence = value + return self.value +@dataclass(frozen=True) class RegisterStackAdjustmentWithConfidence(object): - def __init__(self, value:int, confidence:int=core.max_confidence): - self._value = value - self._confidence = confidence - - def __str__(self): - return str(self._value) - - def __repr__(self): - return repr(self._value) + value:int + confidence:int=core.max_confidence def __int__(self): - return self._value - - @property - def value(self) -> int: - return self._value - - @value.setter - def value(self, value:int) -> None: - self._value = value - - @property - def confidence(self) -> int: - return self._confidence - - @confidence.setter - def confidence(self, value:int) -> None: - self._confidence = value + return self.value +@dataclass(frozen=True) class RegisterSet(object): - def __init__(self, reg_list:List['architecture.RegisterName'], confidence:int=core.max_confidence): - self._regs = reg_list - self._confidence = confidence - - def __repr__(self): - return repr(self._regs) + regs:List['architecture.RegisterName'] + confidence:int=core.max_confidence def __iter__(self) -> Generator['architecture.RegisterName', None, None]: - for reg in self._regs: + for reg in self.regs: yield reg def __getitem__(self, idx): - return self._regs[idx] + return self.regs[idx] def __len__(self): - return len(self._regs) + return len(self.regs) def with_confidence(self, confidence): - return RegisterSet(list(self._regs), confidence = confidence) - - @property - def regs(self) -> List['architecture.RegisterName']: - return self._regs - - @regs.setter - def regs(self, value:List['architecture.RegisterName']) -> None: - self._regs = value - - @property - def confidence(self) -> int: - return self._confidence - - @confidence.setter - def confidence(self, value:int) -> None: - self._confidence = value - - -class ReferenceTypeWithConfidence(object): - def __init__(self, value, confidence = core.max_confidence): - self._value = value - self._confidence = confidence - - def __str__(self): - return str(self._value) - - def __repr__(self): - return repr(self._value) - - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = value - - @property - def confidence(self): - return self._confidence - - @confidence.setter - def confidence(self, value): - self._confidence = value + return RegisterSet(list(self.regs), confidence=confidence) class NamedTypeReference(object): @@ -1223,75 +1083,17 @@ class NamedTypeReference(object): return NamedTypeReference(type_class, type_id, name) +@dataclass(frozen=True) class StructureMember(object): - def __init__(self, t, name, offset): - self._type = t - self._name = name - self._offset = offset + type:'types.Type' + name:str + offset:int def __repr__(self): - if len(self._name) == 0: - return "<member: %s, offset %#x>" % (str(self._type), self._offset) - return "<%s %s%s, offset %#x>" % (self._type.get_string_before_name(), self._name, - self._type.get_string_after_name(), self._offset) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._type, self._name, self._offset) == (other._type, other._name, other._offset) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self._offset < other._offset - - def __gt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self._offset > other._offset - - def __le__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self._offset <= other._offset - - def __ge__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self._offset >= other._offset - - def __hash__(self): - return hash((self._type, self._name, self._offset)) - - @property - def type(self): - return self._type - - @type.setter - def type(self, value): - self._type = value - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value - - @property - def offset(self): - return self._offset - - @offset.setter - def offset(self, value): - self._offset = value - + if len(self.name) == 0: + return f"<member: {self.type}, offset {self.offset:#x}>" + return f"<{self.type.get_string_before_name()} {self.name}{self.type.get_string_after_name()}" + \ + ", offset {self.offset:#x}>" class Structure(object): def __init__(self, handle=None): @@ -1326,30 +1128,34 @@ class Structure(object): def __hash__(self): return hash(ctypes.addressof(self._handle.contents)) - def __getitem__(self, name): + def __getitem__(self, name:str) -> StructureMember: member = None try: if self._mutable: member = core.BNGetStructureBuilderMemberByName(self._handle, name) - assert member is not None, "core.BNGetStructureBuilderMemberByName returned None" + if member is None: + raise ValueError(f"Member {name} is not part of structure") else: member = core.BNGetStructureMemberByName(self._handle, name) - assert member is not None, "core.BNGetStructureMemberByName returned None" + if member is None: + raise ValueError(f"Member {name} is not part of structure") return StructureMember(Type(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) finally: if member is not None: core.BNFreeStructureMember(member) - def member_at_offset(self, offset): + def member_at_offset(self, offset:int) -> StructureMember: member = None try: if self._mutable: member = core.BNGetStructureBuilderMemberAtOffset(self._handle, offset, None) - assert member is not None, "core.BNGetStructureBuilderMemberAtOffset returned None" + if member is None: + raise ValueError(f"No member exists a offset {offset}") else: member = core.BNGetStructureMemberAtOffset(self._handle, offset, None) - assert member is not None, "core.BNGetStructureMemberAtOffset returned None" + if member is None: + raise ValueError(f"No member exists a offset {offset}") return StructureMember(Type(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) finally: @@ -1485,38 +1291,14 @@ class Structure(object): return Structure(core.BNStructureWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) +@dataclass(frozen=True) class EnumerationMember(object): - def __init__(self, name, value, default): - self.name = name - self.value = value - self.default = default + name:str + value:int + default:bool def __repr__(self): - return "<%s = %#x>" % (self.name, self.value) - - @property - def value(self): - return self._value - - @value.setter - def value(self, value): - self._value = value - - @property - def name(self): - return self._name - - @name.setter - def name(self, value): - self._name = value - - @property - def default(self): - return self._default - - @default.setter - def default(self, value): - self._default = value + return f"<{self.name} = {self.value:#x}>" class Enumeration(object): @@ -1603,18 +1385,15 @@ class Enumeration(object): return Enumeration(core.BNCreateEnumerationBuilderFromEnumeration(self._handle)) +@dataclass(frozen=True) class TypeParserResult(object): - def __init__(self, types, variables, functions): - self._types = types - self._variables = variables - self._functions = functions + types:Mapping[QualifiedName, Type] + variables:Mapping[QualifiedName, Type] + functions:Mapping[QualifiedName, Type] def __repr__(self): - return "<types: %s, variables: %s, functions: %s>" % (self._types, self._variables, self._functions) + return "<types: %s, variables: %s, functions: %s>" % (self.types, self.variables, self.functions) - @property - def types(self): - return self._types @types.setter def types(self, value): @@ -1673,102 +1452,16 @@ def preprocess_source(source, filename=None, include_dirs=[]): return (None, error_str) +@dataclass(frozen=True) class TypeFieldReference(object): - def __init__(self, func, arch, addr, size): - self._function = func - self._arch = arch - self._address = addr - self._size = size + func:Optional['function.Function'] + arch:Optional['architecture.Architecture'] + address:int + size:int + incomingType:Type def __repr__(self): - if self._arch: - return "<ref: %s@%#x, size: %#x>" % (self._arch.name, self._address, self._size) - else: - return "<ref: %#x, size: %#x>" % (self._address, self._size) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self.function, self.arch, self.address, self._size) ==\ - (other.address, other.function, other.arch, other.size) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address < other.address: - return True - elif self.address > other.address: - return False - else: - return self.size < other.size - - def __gt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address > other.address: - return True - elif self.address < other.address: - return False - else: - return self.size > other.size - - def __ge__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address > other.address: - return True - elif self.address < other.address: - return False + if self.arch: + return "<ref: %s@%#x, size: %#x>" % (self.arch.name, self.address, self.size) else: - return self.size >= other.size - - def __le__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address < other.address: - return True - elif self.address > other.address: - return False - else: - return self.size <= other.size - - def __hash__(self): - return hash((self._function, self._arch, self._address, self._size)) - - @property - def function(self): - return self._function - - @function.setter - def function(self, value): - self._function = value - - @property - def arch(self): - return self._arch - - @arch.setter - def arch(self, value): - self._arch = value - - @property - def address(self): - return self._address - - @address.setter - def address(self, value): - self._address = value - - @property - def size(self): - return self._size - - @size.setter - def size(self, value): - self._size = value - + return "<ref: %#x, size: %#x>" % (self.address, self.size)
\ No newline at end of file diff --git a/python/variable.py b/python/variable.py index 0b793c15..1e496797 100644 --- a/python/variable.py +++ b/python/variable.py @@ -21,7 +21,7 @@ import ctypes from typing import List, Generator, Optional, Union, Set, Mapping -from dataclasses import dataclass +from dataclasses import dataclass, field import binaryninja from . import _binaryninjacore as core @@ -39,9 +39,6 @@ class LookupTableEntry(object): def type(self): return RegisterValueType.LookupTableValue -@dataclass(frozen=True) -class Confidence: - confidence:int=core.max_confidence @dataclass(frozen=True) class RegisterValue: @@ -52,16 +49,14 @@ class RegisterValue: def _to_api_object(self): result = core.BNRegisterValue() - result.type = self.type - result._value = self.value + result.state = self.type + result.value = self.value result.offset = self.offset return result def _to_api_object_with_confidence(self): - result = core.BNRegisterValue() - result.type = self.type - result._value = self.value - result.offset = self.offset + result = core.BNRegisterValueWithConfidence() + result.value = self._to_api_object() result.confidence = self.confidence return result @@ -87,6 +82,7 @@ class RegisterValue: confidence = core.max_confidence if isinstance(reg_value, core.BNRegisterValueWithConfidence): confidence = reg_value.confidence + reg_value = reg_value.value if reg_value.state == RegisterValueType.EntryValue: reg = None if arch is not None: @@ -94,14 +90,18 @@ class RegisterValue: return EntryRegisterValue(reg_value.value, reg=reg, confidence=confidence) elif reg_value.state == RegisterValueType.ConstantValue: return ConstantRegisterValue(reg_value.value, confidence=confidence) - elif reg_value.state == RegisterValueType.ConstantValue: + elif reg_value.state == RegisterValueType.ConstantPointerValue: return ConstantPointerRegisterValue(reg_value.value, confidence=confidence) elif reg_value.state == RegisterValueType.StackFrameOffset: - return StackFrameOffsetRegisterValue(reg_value.value, reg_value.offset, confidence=confidence) + return StackFrameOffsetRegisterValue(reg_value.value, confidence=confidence) elif reg_value.state == RegisterValueType.ImportedAddressValue: return ImportedAddressRegisterValue(reg_value.value, confidence=confidence) elif reg_value.state == RegisterValueType.UndeterminedValue: return Undetermined() + elif reg_value.state == RegisterValueType.ReturnAddressValue: + return ReturnAddressRegisterValue(reg_value.value, confidence=confidence) + elif reg_value.state == RegisterValueType.ExternalPointerValue: + return ExternalPointerRegisterValue(reg_value.value, reg_value.offset, confidence=confidence) assert False, f"RegisterValueType {reg_value.state} not handled" @@ -111,6 +111,9 @@ class Undetermined(RegisterValue): offset:int = 0 type:RegisterValueType = RegisterValueType.UndeterminedValue + def __repr__(self): + return "<undetermined>" + @dataclass(frozen=True, eq=False) class ConstantRegisterValue(RegisterValue): @@ -156,19 +159,18 @@ class EntryRegisterValue(RegisterValue): reg:Optional['binaryninja.architecture.RegisterName'] = None def __repr__(self): + if self.reg is not None: + return f"<entry {self.reg}>" return f"<entry {self.value}>" - @classmethod - def from_BNRegisterValue(cls, value:core.BNRegisterValue): - cls(value.state, value.value, value.offset) - @dataclass(frozen=True, eq=False) class StackFrameOffsetRegisterValue(RegisterValue): + offset:int = 0 type:RegisterValueType = RegisterValueType.StackFrameOffset def __repr__(self): - return f"<stack frame offset {self.offset:#x}>" + return f"<stack frame offset {self.value:#x}>" @dataclass(frozen=True, eq=False) class ExternalPointerRegisterValue(RegisterValue): @@ -177,39 +179,22 @@ class ExternalPointerRegisterValue(RegisterValue): def __repr__(self): return f"<external {self.value:#x} + offset {self.offset:#x}>" -@decorators.passive + +@dataclass(frozen=True) class ValueRange(object): - def __init__(self, start, end, step): - self._start = start - self._end = end - self._step = step + start:int + end:int + step:int def __repr__(self): if self.step == 1: return f"<range: {self.start:#x} to {self.end:#x}>" return f"<range: {self.start:#x} to {self.end:#x}, step {self.step:#x}>" - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.start == other.start and self.end == other.end and self.step == other.step - def __contains__(self, other): if not isinstance(other, int): return NotImplemented - return other in range(self._start, self._end, self._step) - - @property - def start(self): - return self._start - - @property - def end(self): - return self._end - - @property - def step(self): - return self._step + return other in range(self.start, self.end, self.step) @decorators.passive @@ -390,7 +375,8 @@ class PossibleValueSet(object): for value in self.values: values[i] = value i += 1 - result.valueSet = ctypes.cast(values, ctypes.POINTER(ctypes.c_longlong)) + int_ptr = ctypes.POINTER(ctypes.c_longlong) + result.valueSet = ctypes.cast(values, int_ptr) result.count = self.count return result @@ -566,67 +552,31 @@ class PossibleValueSet(object): return result -@decorators.passive +@dataclass(frozen=True) class StackVariableReference(object): - def __init__(self, src_operand, t, name, var, ref_ofs, size): - self._source_operand = src_operand - self._type = t - self._name = name - self._var = var - self._referenced_offset = ref_ofs - self._size = size - if self._source_operand == 0xffffffff: - self._source_operand = None + _source_operand:Optional[int] + type:'binaryninja.types.Type' + name:str + var:'Variable' + referenced_offset:int + size:int def __repr__(self): - if self._source_operand is None: - if self._referenced_offset != self._var.storage: - return "<ref to %s%+#x>" % (self._name, self._referenced_offset - self._var.storage) - return "<ref to %s>" % self._name - if self._referenced_offset != self._var.storage: - return "<operand %d ref to %s%+#x>" % (self._source_operand, self._name, self._var.storage) - return "<operand %d ref to %s>" % (self._source_operand, self._name) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._source_operand, self._type, self._name, self._var, self._referenced_offset, self._size) == \ - (other._source_operand, other._type, other._name, other._var, other._referenced_offset, other._size) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._source_operand, self._type, self._name, self._var, self._referenced_offset, self._size)) + if self.source_operand is None: + if self.referenced_offset != self.var.storage: + return f"<ref to {self.name}{self.referenced_offset - self.var.storage:+#x}>" + return f"<ref to {self.name}>" + if self.referenced_offset != self.var.storage: + return f"<operand {self.source_operand} ref to {self.var.storage}{self.var.storage:+#x}>" + return f"<operand {self.source_operand} ref to {self.name}>" @property def source_operand(self): + if self._source_operand == 0xffffffff: + return None return self._source_operand - @property - def type(self): - return self._type - - @property - def name(self): - return self._name - @property - def var(self): - return self._var - - @property - def referenced_offset(self): - return self._referenced_offset - - @property - def size(self): - return self._size - - -@decorators.passive @dataclass(frozen=True, order=True) class CoreVariable: _source_type:int @@ -657,7 +607,7 @@ class CoreVariable: var = core.BNFromVariableIdentifier(identifier) return cls(var.type, var.index, var.storage) -@decorators.passive + @dataclass(frozen=True, order=True) class VariableNameAndType(CoreVariable): name:str @@ -792,13 +742,12 @@ class Variable: def to_BNVariable(self): return self._var.to_BNVariable() -@decorators.passive +@dataclass(frozen=True) class ConstantReference(object): - def __init__(self, val, size, ptr, intermediate): - self._value = val - self._size = size - self._pointer = ptr - self._intermediate = intermediate + value:int + size:int + pointer:bool + intermediate:bool def __repr__(self): if self.pointer: @@ -807,45 +756,17 @@ class ConstantReference(object): return "<constant %#x>" % self.value return "<constant %#x size %d>" % (self.value, self.size) - @property - def value(self): - return self._value - - @property - def size(self): - return self._size - - @property - def pointer(self): - return self._pointer - - @property - def intermediate(self): - return self._intermediate - - -@decorators.passive -class UserVariableValueInfo(object): - def __init__(self, var, def_site, value): - self.var = var - self.def_site = def_site - self.value = value - - def __repr__(self): - return "<user value for %s @ %s:%#x -> %s>" % (self.var, self.def_site.arch.name, self.def_site.addr, self.value) - -@decorators.passive +@dataclass(frozen=True) class IndirectBranchInfo(object): - def __init__(self, source_arch, source_addr, dest_arch, dest_addr, auto_defined): - self.source_arch = source_arch - self.source_addr = source_addr - self.dest_arch = dest_arch - self.dest_addr = dest_addr - self.auto_defined = auto_defined + source_arch:'binaryninja.architecture.Architecture' + source_addr:int + dest_arch:'binaryninja.architecture.Architecture' + dest_addr:int + auto_defined:bool def __repr__(self): - return "<branch %s:%#x -> %s:%#x>" % (self.source_arch.name, self.source_addr, self.dest_arch.name, self.dest_addr) + return f"<branch {self.source_arch.name}:{self.source_addr:#x} -> {self.dest_arch.name}:{self.dest_addr:#x}>" @decorators.passive @@ -889,39 +810,10 @@ class ParameterVariables(object): return self._func -@decorators.passive +@dataclass(frozen=True, order=True) class AddressRange(object): - def __init__(self, start:int, end:int): - self._start = start - self._end = end + start:int + end:int def __repr__(self): - return "<%#x-%#x>" % (self._start, self._end) - - def __len__(self): - return self._end - self.start - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._start, self._end) == (other._start, other._end) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._start, self._end)) - - @property - def length(self) -> int: - return self._end - self._start - - @property - def start(self) -> int: - return self._start - - @property - def end(self) -> int: - return self._end
\ No newline at end of file + return f"<{self.start:#x}-{self.end:#x}>"
\ No newline at end of file |
