summaryrefslogtreecommitdiff
path: root/python/lowlevelil.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/lowlevelil.py')
-rw-r--r--python/lowlevelil.py427
1 files changed, 97 insertions, 330 deletions
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):