summaryrefslogtreecommitdiff
path: root/python/variable.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/variable.py')
-rw-r--r--python/variable.py953
1 files changed, 953 insertions, 0 deletions
diff --git a/python/variable.py b/python/variable.py
new file mode 100644
index 00000000..187d5e3d
--- /dev/null
+++ b/python/variable.py
@@ -0,0 +1,953 @@
+# coding=utf-8
+# Copyright (c) 2015-2021 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import ctypes
+from typing import List, Generator, Optional, Union, Set, Mapping
+
+import binaryninja
+from . import _binaryninjacore as core
+from . import decorators
+from .enums import RegisterValueType, VariableSourceType, DeadStoreElimination
+
+
+@decorators.passive
+class LookupTableEntry(object):
+ def __init__(self, from_values:List[int], to_value):
+ self._from_values = from_values
+ self._to_value = to_value
+
+ def __repr__(self):
+ return f"[{', '.join([f'{i:#x}' for i in self.from_values])}] -> {self.to_value:#x}"
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self._from_values, self._to_value) == (other._from_values, other._to_value)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self._from_values, self._to_value))
+
+ @property
+ def from_values(self):
+ return self._from_values
+
+ @property
+ def to_value(self):
+ return self._to_value
+
+
+@decorators.passive
+class RegisterValue(object):
+ def __init__(self, arch:Optional['binaryninja.architecture.Architecture']=None,
+ value:core.BNRegisterValue=None, confidence:int=core.max_confidence):
+ self._is_constant = False
+ self._value = None
+ self._arch = None
+ # self._reg:Optional[Union[binaryninja.architecture.RegisterName, binaryninja.architecture.RegisterIndex]] = None
+ self._is_constant = False
+ self._offset = None
+ if value is None:
+ self._type = RegisterValueType.UndeterminedValue
+ else:
+ assert isinstance(value.value, int), "BNRegisterValue.value isn't an integer"
+ self._type = RegisterValueType(value.state)
+ if value.state == RegisterValueType.EntryValue:
+ self._arch = arch
+ if arch is not None:
+ self._value = arch.get_reg_name(binaryninja.architecture.RegisterIndex(value.value))
+ else:
+ self._value = value.value
+ elif (value.state == RegisterValueType.ConstantValue) or (value.state == RegisterValueType.ConstantPointerValue):
+ self._value = value.value
+ self._is_constant = True
+ elif value.state == RegisterValueType.StackFrameOffset:
+ self._offset = value.value
+ elif value.state == RegisterValueType.ImportedAddressValue:
+ self._value = value.value
+ self._confidence = confidence
+
+ def __repr__(self):
+ if self._type == RegisterValueType.EntryValue:
+ return f"<entry {self._value:s}>"
+ if self._type == RegisterValueType.ConstantValue:
+ return f"<const {self._value:#x}>"
+ if self._type == RegisterValueType.ConstantPointerValue:
+ return f"<const ptr {self._value:#x}>"
+ if self._type == RegisterValueType.StackFrameOffset:
+ return f"<stack frame offset {self._offset:#x}>"
+ if self._type == RegisterValueType.ReturnAddressValue:
+ return "<return address>"
+ if self._type == RegisterValueType.ImportedAddressValue:
+ return f"<imported address from entry {self._value:#x}>"
+ return "<undetermined>"
+
+ def __hash__(self):
+ if self._type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue, RegisterValueType.ImportedAddressValue, RegisterValueType.ReturnAddressValue, RegisterValueType.EntryValue]:
+ return hash(self._value)
+ elif self._type == RegisterValueType.StackFrameOffset:
+ return hash(self._offset)
+
+ def __eq__(self, other):
+ if self._type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue, RegisterValueType.ImportedAddressValue, RegisterValueType.ReturnAddressValue] and isinstance(other, int):
+ return self._value == other
+ elif self._type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue, RegisterValueType.ImportedAddressValue, RegisterValueType.ReturnAddressValue] and hasattr(other, 'type') and other.type == self._type:
+ return self._value == other.value
+ elif self._type == RegisterValueType.EntryValue and hasattr(other, "type") and other.type == self._type:
+ return self._value == other.reg
+ elif self._type == RegisterValueType.StackFrameOffset and hasattr(other, 'type') and other.type == self._type:
+ return self._offset == other.offset
+ elif self._type == RegisterValueType.StackFrameOffset and isinstance(other, int):
+ return self._offset == other
+ return NotImplemented
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def _to_api_object(self):
+ result = core.BNRegisterValue()
+ result.type = self._type
+ result._value = 0
+ if self._type == RegisterValueType.EntryValue:
+ if isinstance(self._value, binaryninja.architecture.RegisterName):
+ if self._arch is None:
+ raise Exception("Can not convert Variable to API object without an Architecture set")
+ result._value = self._arch.get_reg_index(self._value)
+ else:
+ result._value = self._value
+ elif (self._type == RegisterValueType.ConstantValue) or (self._type == RegisterValueType.ConstantPointerValue):
+ result._value = self._value
+ elif self._type == RegisterValueType.StackFrameOffset:
+ result._value = self._offset
+ elif self._type == RegisterValueType.ImportedAddressValue:
+ result._value = self._value
+ return result
+
+ @classmethod
+ def undetermined(cls):
+ return RegisterValue()
+
+ @classmethod
+ def entry_value(cls, arch:'binaryninja.architecture.Architecture', reg:'binaryninja.architecture.RegisterName') -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.EntryValue
+ result._arch = arch
+ result._value = reg
+ return result
+
+ @staticmethod
+ def constant(value:int) -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.ConstantValue
+ result._value = value
+ result._is_constant = True
+ return result
+
+ @staticmethod
+ def constant_ptr(value:int) -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.ConstantPointerValue
+ result._value = value
+ result._is_constant = True
+ return result
+
+ @staticmethod
+ def stack_frame_offset(offset:int) -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.StackFrameOffset
+ result._offset = offset
+ return result
+
+ @staticmethod
+ def imported_address(value) -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.ImportedAddressValue
+ result._value = value
+ return result
+
+ @staticmethod
+ def return_address() -> 'RegisterValue':
+ result = RegisterValue()
+ result._type = RegisterValueType.ReturnAddressValue
+ return result
+
+ @property
+ def is_constant(self) -> bool:
+ """Boolean for whether the RegisterValue is known to be constant (read-only)"""
+ return self._is_constant
+
+ @property
+ def type(self) -> RegisterValueType:
+ """:class:`~enums.RegisterValueType` (read-only)"""
+ return self._type
+
+ @property
+ def arch(self) -> Optional['binaryninja.architecture.Architecture']:
+ """Architecture where it exists, None otherwise (read-only)"""
+ return self._arch
+
+ @property
+ def reg(self) -> 'binaryninja.architecture.RegisterName':
+ """Register Name where the Architecture exists raises exception otherwise (read-only)"""
+ if not isinstance(self._value, binaryninja.architecture.RegisterName):
+ raise Exception("Attempting to access register when property doesn't exist")
+ return self._value
+
+ @property
+ def value(self) -> Optional[Union[int, 'binaryninja.architecture.RegisterName']]:
+ """Value where it exists, None otherwise (read-only)"""
+ return self._value
+
+ @property
+ def offset(self) -> Optional[int]:
+ """Offset where it exists, None otherwise (read-only)"""
+ return self._offset
+
+ @property
+ def confidence(self) -> Optional[int]:
+ """Confidence where it exists, None otherwise (read-only)"""
+ return self._confidence
+
+
+@decorators.passive
+class ValueRange(object):
+ def __init__(self, start, end, step):
+ self._start = start
+ self._end = end
+ self._step = step
+
+ 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
+
+
+@decorators.passive
+class PossibleValueSet(object):
+ """
+ `class PossibleValueSet` PossibleValueSet is used to define possible values
+ that a variable can take. It contains methods to instantiate different
+ value sets such as Constant, Signed/Unsigned Ranges, etc.
+ """
+ def __init__(self, arch = None, value = None):
+ if value is None:
+ self._type = RegisterValueType.UndeterminedValue
+ return
+ self._type = RegisterValueType(value.state)
+ if value.state == RegisterValueType.EntryValue:
+ if arch is None:
+ self._reg = value.value
+ else:
+ self._reg = arch.get_reg_name(value.value)
+ elif value.state == RegisterValueType.ConstantValue:
+ self._value = value.value
+ elif value.state == RegisterValueType.ConstantPointerValue:
+ self._value = value.value
+ elif value.state == RegisterValueType.StackFrameOffset:
+ self._offset = value.value
+ elif value.state == RegisterValueType.SignedRangeValue:
+ self._offset = value.value
+ self._ranges = []
+ for i in range(0, value.count):
+ start = value.ranges[i].start
+ end = value.ranges[i].end
+ step = value.ranges[i].step
+ if start & (1 << 63):
+ start |= ~((1 << 63) - 1)
+ if end & (1 << 63):
+ end |= ~((1 << 63) - 1)
+ self._ranges.append(ValueRange(start, end, step))
+ elif value.state == RegisterValueType.UnsignedRangeValue:
+ self._offset = value.value
+ self._ranges = []
+ for i in range(0, value.count):
+ start = value.ranges[i].start
+ end = value.ranges[i].end
+ step = value.ranges[i].step
+ self._ranges.append(ValueRange(start, end, step))
+ elif value.state == RegisterValueType.LookupTableValue:
+ self._table = []
+ self._mapping = {}
+ for i in range(0, value.count):
+ from_list = []
+ for j in range(0, value.table[i].fromCount):
+ from_list.append(value.table[i].fromValues[j])
+ self._mapping[value.table[i].fromValues[j]] = value.table[i].toValue
+ self._table.append(LookupTableEntry(from_list, value.table[i].toValue))
+ elif (value.state == RegisterValueType.InSetOfValues) or (value.state == RegisterValueType.NotInSetOfValues):
+ self._values = set()
+ for i in range(0, value.count):
+ self._values.add(value.valueSet[i])
+ self._count = value.count
+
+ def __repr__(self):
+ if self._type == RegisterValueType.EntryValue:
+ return f"<entry {self.reg}>"
+ if self._type == RegisterValueType.ConstantValue:
+ return f"<const {self.value:#x}>"
+ if self._type == RegisterValueType.ConstantPointerValue:
+ return f"<const ptr {self.value:#x}>"
+ if self._type == RegisterValueType.StackFrameOffset:
+ return f"<stack frame offset {self._offset:#x}>"
+ if self._type == RegisterValueType.SignedRangeValue:
+ return f"<signed ranges: {repr(self.ranges)}>"
+ if self._type == RegisterValueType.UnsignedRangeValue:
+ return f"<unsigned ranges: {repr(self.ranges)}>"
+ if self._type == RegisterValueType.LookupTableValue:
+ return f"<table: {', '.join([repr(i) for i in self.table])}>"
+ if self._type == RegisterValueType.InSetOfValues:
+ return f"<in set([{', '.join(hex(i) for i in sorted(self.values))}])>"
+ if self._type == RegisterValueType.NotInSetOfValues:
+ return f"<not in set([{', '.join(hex(i) for i in sorted(self.values))}])>"
+ if self._type == RegisterValueType.ReturnAddressValue:
+ return "<return address>"
+ return "<undetermined>"
+
+ def __contains__(self, other):
+ if self.type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue] and isinstance(other, int):
+ return self.value == other
+ if self.type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue] and hasattr(other, "value"):
+ return self.value == other.value
+ if not isinstance(other, int):
+ return NotImplemented
+ #Initial implementation only checks numbers, no set logic
+ if self.type == RegisterValueType.StackFrameOffset:
+ return NotImplemented
+ if self.type in [RegisterValueType.SignedRangeValue, RegisterValueType.UnsignedRangeValue]:
+ for rng in self.ranges:
+ if other in rng:
+ return True
+ return False
+ if self.type == RegisterValueType.InSetOfValues:
+ return other in self.values
+ if self.type == RegisterValueType.NotInSetOfValues:
+ return not other in self.values
+ return NotImplemented
+
+ def __eq__(self, other):
+ if self.type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue] and isinstance(other, int):
+ return self.value == other
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ if self.type in [RegisterValueType.ConstantValue, RegisterValueType.ConstantPointerValue]:
+ return self.value == other.value
+ elif self.type == RegisterValueType.StackFrameOffset:
+ return self.offset == other.offset
+ elif self.type in [RegisterValueType.SignedRangeValue, RegisterValueType.UnsignedRangeValue]:
+ return self.ranges == other.ranges
+ elif self.type in [RegisterValueType.InSetOfValues, RegisterValueType.NotInSetOfValues]:
+ return self.values == other.values
+ elif self.type == RegisterValueType.UndeterminedValue and hasattr(other, 'type'):
+ return self.type == other.type
+ else:
+ return self == other
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def _to_api_object(self):
+ result = core.BNPossibleValueSet()
+ result.state = RegisterValueType(self.type)
+ if self.type == RegisterValueType.UndeterminedValue:
+ return result
+ elif self.type == RegisterValueType.ConstantValue:
+ result.value = self.value
+ elif self.type == RegisterValueType.ConstantPointerValue:
+ result.value = self.value
+ elif self.type == RegisterValueType.StackFrameOffset:
+ result.offset = self.value
+ elif self.type == RegisterValueType.SignedRangeValue:
+ result.offset = self.value
+ result.ranges = (core.BNValueRange * self.count)()
+ for i in range(0, self.count):
+ start = self.ranges[i].start
+ end = self.ranges[i].end
+ if start & (1 << 63):
+ start |= ~((1 << 63) - 1)
+ if end & (1 << 63):
+ end |= ~((1 << 63) - 1)
+ value_range = core.BNValueRange()
+ value_range.start = start
+ value_range.end = end
+ value_range.step = self.ranges[i].step
+ result.ranges[i] = value_range
+ result.count = self.count
+ elif self.type == RegisterValueType.UnsignedRangeValue:
+ result.offset = self.value
+ result.ranges = (core.BNValueRange * self.count)()
+ for i in range(0, self.count):
+ value_range = core.BNValueRange()
+ value_range.start = self.ranges[i].start
+ value_range.end = self.ranges[i].end
+ value_range.step = self.ranges[i].step
+ result.ranges[i] = value_range
+ result.count = self.count
+ elif self.type == RegisterValueType.LookupTableValue:
+ result.table = []
+ result.mapping = {}
+ for i in range(self.count):
+ from_list = []
+ for j in range(0, len(self.table[i].from_values)):
+ from_list.append(self.table[i].from_values[j])
+ result.mapping[self.table[i].from_values[j]] = result.table[i].to_value
+ result.table.append(LookupTableEntry(from_list, result.table[i].to_value))
+ result.count = self.count
+ elif (self.type == RegisterValueType.InSetOfValues) or (self.type == RegisterValueType.NotInSetOfValues):
+ values = (ctypes.c_longlong * self.count)()
+ i = 0
+ for value in self.values:
+ values[i] = value
+ i += 1
+ result.valueSet = ctypes.cast(values, ctypes.POINTER(ctypes.c_longlong))
+ result.count = self.count
+ return result
+
+ @property
+ def type(self) -> RegisterValueType:
+ return self._type
+
+ @property
+ def reg(self) -> 'binaryninja.architecture.RegisterName':
+ return self._reg
+
+ @property
+ def value(self) -> int:
+ return self._value
+
+ @property
+ def offset(self) -> int:
+ return self._offset
+
+ @property
+ def ranges(self) -> List[ValueRange]:
+ return self._ranges
+
+ @property
+ def table(self) -> List[LookupTableEntry]:
+ return self._table
+
+ @property
+ def mapping(self) -> Mapping[int, int]:
+ return self._mapping
+
+ @property
+ def values(self) -> Set[int]:
+ return self._values
+
+ @property
+ def count(self) -> int:
+ return self._count
+
+ @staticmethod
+ def undetermined() -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object of type UndeterminedValue.
+
+ :return: PossibleValueSet object of type UndeterminedValue
+ :rtype: PossibleValueSet
+ """
+ return PossibleValueSet()
+
+ @staticmethod
+ def constant(value:int) -> 'PossibleValueSet':
+ """
+ Create a constant valued PossibleValueSet object.
+
+ :param int value: Integer value of the constant
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.ConstantValue
+ result._value = value
+ return result
+
+ @staticmethod
+ def constant_ptr(value:int) -> 'PossibleValueSet':
+ """
+ Create constant pointer valued PossibleValueSet object.
+
+ :param int value: Integer value of the constant pointer
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.ConstantPointerValue
+ result._value = value
+ return result
+
+ @staticmethod
+ def stack_frame_offset(offset:int) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a stack frame offset.
+
+ :param int value: Integer value of the offset
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.StackFrameOffset
+ result._offset = offset
+ return result
+
+ @staticmethod
+ def signed_range_value(ranges:List[ValueRange]) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a signed range of values.
+
+ :param list(ValueRange) ranges: List of ValueRanges
+ :rtype: PossibleValueSet
+ :Example:
+
+ >>> v_1 = ValueRange(-5, -1, 1)
+ >>> v_2 = ValueRange(7, 10, 1)
+ >>> val = PossibleValueSet.signed_range_value([v_1, v_2])
+ <signed ranges: [<range: -0x5 to -0x1>, <range: 0x7 to 0xa>]>
+ """
+ result = PossibleValueSet()
+ result._value = 0
+ result._type = RegisterValueType.SignedRangeValue
+ result._ranges = ranges
+ result._count = len(ranges)
+ return result
+
+ @staticmethod
+ def unsigned_range_value(ranges:List[ValueRange]) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a unsigned signed range of values.
+
+ :param list(ValueRange) ranges: List of ValueRanges
+ :rtype: PossibleValueSet
+ :Example:
+
+ >>> v_1 = ValueRange(0, 5, 1)
+ >>> v_2 = ValueRange(7, 10, 1)
+ >>> val = PossibleValueSet.unsigned_range_value([v_1, v_2])
+ <unsigned ranges: [<range: 0x0 to 0x5>, <range: 0x7 to 0xa>]>
+ """
+ result = PossibleValueSet()
+ result._value = 0
+ result._type = RegisterValueType.UnsignedRangeValue
+ result._ranges = ranges
+ result._count = len(ranges)
+ return result
+
+ @staticmethod
+ def in_set_of_values(values:Union[List[int], Set[int]]) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a value in a set of values.
+
+ :param list(int) values: List of integer values
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.InSetOfValues
+ result._values = set(values)
+ result._count = len(values)
+ return result
+
+ @staticmethod
+ def not_in_set_of_values(values) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a value NOT in a set of values.
+
+ :param list(int) values: List of integer values
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.NotInSetOfValues
+ result._values = set(values)
+ result._count = len(values)
+ return result
+
+ @staticmethod
+ def lookup_table_value(lookup_table, mapping) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a value which is a member of a
+ lookuptable.
+
+ :param list(LookupTableEntry) lookup_table: List of table entries
+ :param dict of (int, int) mapping: Mapping used for resolution
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.LookupTableValue
+ result._table = lookup_table
+ result._mapping = mapping
+ return result
+
+
+@decorators.passive
+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
+
+ 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))
+
+ @property
+ def source_operand(self):
+ 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
+class Variable(object):
+ def __init__(self, func, source_type, index, storage, name = None, var_type = None, identifier = None):
+ self._function = func
+ self._source_type = source_type
+ self._index = index
+ self._storage = storage
+ self._identifier = identifier
+ self._name = name
+ self._type = var_type
+
+ def __repr__(self):
+ if self.type is not None:
+ return f"<var {self.type.get_string_before_name()} {self.name}{self.type.get_string_after_name()}>"
+ else:
+ return f"<var {self.name}>"
+
+ def __str__(self):
+ return self.name
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self.identifier, self.function) == (other.identifier, other.function)
+
+ 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.identifier, self.function) < (other.identifier, other.function)
+
+ def __gt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self.identifier, self.function) > (other.identifier, other.function)
+
+ def __le__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self.identifier, self.function) <= (other.identifier, other.function)
+
+ def __ge__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return (self.identifier, self.function) >= (other.identifier, other.function)
+
+ def __hash__(self):
+ return hash((self.identifier, self.function))
+
+ @property
+ def function(self) -> 'binaryninja.function.Function':
+ """Function where the variable is defined"""
+ return self._function
+
+ @function.setter
+ def function(self, value:'binaryninja.function.Function'):
+ self._function = value
+
+ @property
+ def source_type(self) -> VariableSourceType:
+ """:class:`~enums.VariableSourceType`"""
+ if not isinstance(self._source_type, VariableSourceType):
+ self._source_type = VariableSourceType(self._source_type)
+
+ return self._source_type
+
+ @source_type.setter
+ def source_type(self, value:VariableSourceType) -> None:
+ self._source_type = value
+
+ @property
+ def index(self) -> int:
+ return self._index
+
+ @index.setter
+ def index(self, value:int) -> None:
+ self._index = value
+
+ @property
+ def storage(self) -> int:
+ """Stack offset for StackVariableSourceType, register index for RegisterVariableSourceType"""
+ return self._storage
+
+ @storage.setter
+ def storage(self, value:int) -> None:
+ self._storage = value
+
+ @property
+ def identifier(self) -> int:
+ if self._identifier is None:
+ self._identifier = core.BNToVariableIdentifier(self.to_BNVariable())
+ return self._identifier
+
+ @property
+ def name(self):
+ """Name of the variable"""
+ if self._name is None:
+ if self._function is not None:
+ self._name = core.BNGetVariableName(self._function.handle, self.to_BNVariable())
+ return self._name
+
+ @property
+ def type(self) -> Optional['binaryninja.types.Type']:
+ if self._type is None:
+ if self._function is not None:
+ var_type_conf = core.BNGetVariableType(self._function.handle, self.to_BNVariable())
+ if var_type_conf.type:
+ self._type = binaryninja.types.Type(var_type_conf.type, platform = self._function.platform, confidence = var_type_conf.confidence)
+ return self._type
+
+ def to_BNVariable(self):
+ v = core.BNVariable()
+ v.type = self.source_type
+ v.index = self._index
+ v.storage = self._storage
+ return v
+
+ @property
+ def dead_store_elimination(self):
+ if self._function is not None and self._identifier is not None:
+ return DeadStoreElimination(core.BNGetFunctionVariableDeadStoreElimination(self._function.handle, self.to_BNVariable()))
+ return None
+
+ @dead_store_elimination.setter
+ def dead_store_elimination(self, value):
+ core.BNSetFunctionVariableDeadStoreElimination(self._function.handle, self.to_BNVariable(), value)
+
+ @staticmethod
+ def from_identifier(func, identifier, name=None, var_type=None):
+ var = core.BNFromVariableIdentifier(identifier)
+ return Variable(func, VariableSourceType(var.type), var.index, var.storage, name, var_type, identifier)
+
+@decorators.passive
+class ConstantReference(object):
+ def __init__(self, val, size, ptr, intermediate):
+ self._value = val
+ self._size = size
+ self._pointer = ptr
+ self._intermediate = intermediate
+
+ def __repr__(self):
+ if self.pointer:
+ return "<constant pointer %#x>" % self.value
+ if self.size == 0:
+ 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
+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
+
+ def __repr__(self):
+ return "<branch %s:%#x -> %s:%#x>" % (self.source_arch.name, self.source_addr, self.dest_arch.name, self.dest_addr)
+
+
+@decorators.passive
+class ParameterVariables(object):
+ def __init__(self, var_list:List[Variable], confidence:int=core.max_confidence, func:Optional['binaryninja.function.Function']=None):
+ self._vars = var_list
+ self._confidence = confidence
+ self._func = func
+
+ def __repr__(self):
+ return repr(self._vars)
+
+ def __len__(self):
+ return len(self._vars)
+
+ def __iter__(self) -> Generator['Variable', None, None]:
+ for var in self._vars:
+ yield var
+
+ def __getitem__(self, idx) -> 'Variable':
+ return self._vars[idx]
+
+ def __setitem__(self, idx:int, value:'Variable'):
+ self._vars[idx] = value
+ if self._func is not None:
+ self._func.parameter_vars = self
+
+ def with_confidence(self, confidence:int) -> 'ParameterVariables':
+ return ParameterVariables(list(self._vars), confidence, self._func)
+
+ @property
+ def vars(self) -> List['Variable']:
+ return self._vars
+
+ @property
+ def confidence(self) -> int:
+ return self._confidence
+
+ @property
+ def function(self) -> Optional['binaryninja.function.Function']:
+ return self._func
+
+
+@decorators.passive
+class AddressRange(object):
+ def __init__(self, start:int, end:int):
+ self._start = start
+ self._end = end
+
+ 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