summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2021-06-23 09:31:22 -0400
committerPeter LaFosse <peter@vector35.com>2021-09-05 10:08:09 -0400
commit6de4900db74a341fddfda46f7cb4342fdc31f8e0 (patch)
tree790a990b2b9ccd8229a31754d28a74a2db839851 /python
parentea052d32732f62000164f243a1aad0bb7425199e (diff)
Refactor Variable class
The Variable class is now broken into 3 separate classes with helper methods to convert between them. CoreVariable is implemented as a frozen dataclass and is analogous to BNVariable VariableNameAndType is analogous to BNVariableNameAndType Bothe the above are passive objects and can not be changed directly The new and improved Variable object is now an active object which can be operated on directly and changes will take effect immediately
Diffstat (limited to 'python')
-rw-r--r--python/callingconvention.py54
-rw-r--r--python/function.py102
-rw-r--r--python/highlevelil.py30
-rw-r--r--python/mediumlevelil.py51
-rw-r--r--python/types.py6
-rw-r--r--python/variable.py178
6 files changed, 187 insertions, 234 deletions
diff --git a/python/callingconvention.py b/python/callingconvention.py
index 096a6b73..44573503 100644
--- a/python/callingconvention.py
+++ b/python/callingconvention.py
@@ -372,7 +372,7 @@ class CallingConvention(object):
func_obj = None
else:
func_obj = function.Function(handle = core.BNNewFunctionReference(func))
- in_var_obj = variable.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
+ in_var_obj = variable.CoreVariable.from_BNVariable(in_var[0])
out_var = self.perform_get_incoming_var_for_parameter_var(in_var_obj, func_obj)
result[0].type = out_var.source_type
result[0].index = out_var.index
@@ -389,7 +389,7 @@ class CallingConvention(object):
func_obj = None
else:
func_obj = function.Function(handle = core.BNNewFunctionReference(func))
- in_var_obj = variable.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage)
+ in_var_obj = variable.CoreVariable.from_BNVariable(in_var[0])
out_var = self.perform_get_parameter_var_for_incoming_var(in_var_obj, func_obj)
result[0].type = out_var.source_type
result[0].index = out_var.index
@@ -408,28 +408,19 @@ class CallingConvention(object):
return variable.RegisterValue()
def perform_get_incoming_flag_value(self, reg, func):
- return variable.RegisterValue()
+ return variable.Undetermined()
- def perform_get_incoming_var_for_parameter_var(self, in_var, func):
- in_buf = core.BNVariable()
- in_buf.type = in_var.source_type
- in_buf.index = in_var.index
- in_buf.storage = in_var.storage
- out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_buf)
- name = None
- if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType):
- name = func.arch.get_reg_name(out_var.storage)
- return variable.Variable(func, out_var.type, out_var.index, out_var.storage, name)
+ def perform_get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable',
+ func:Optional['function.Function']=None):
+ out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_var.to_BNVariable())
+ return variable.CoreVariable.from_BNVariable(out_var)
- def perform_get_parameter_var_for_incoming_var(self, in_var, func):
- in_buf = core.BNVariable()
- in_buf.type = in_var.source_type
- in_buf.index = in_var.index
- in_buf.storage = in_var.storage
- out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_buf)
- return variable.Variable(func, out_var.type, out_var.index, out_var.storage)
+ def perform_get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable',
+ func:Optional['function.Function']=None):
+ out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_var.to_BNVariable())
+ return variable.CoreVariable.from_BNVariable(out_var)
- def with_confidence(self, confidence):
+ def with_confidence(self, confidence:int):
return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle),
confidence = confidence)
@@ -447,32 +438,23 @@ class CallingConvention(object):
func_handle = func.handle
return variable.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle))
- def get_incoming_var_for_parameter_var(self, in_var, func):
- in_buf = core.BNVariable()
- in_buf.type = in_var.source_type
- in_buf.index = in_var.index
- in_buf.storage = in_var.storage
+ def get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', func:'function.Function'):
+ in_buf = in_var.to_BNVariable()
if func is None:
func_obj = None
else:
func_obj = func.handle
out_var = core.BNGetIncomingVariableForParameterVariable(self.handle, in_buf, func_obj)
- name = None
- if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType):
- name = func.arch.get_reg_name(out_var.storage)
- return variable.Variable(func, out_var.type, out_var.index, out_var.storage, name)
+ return variable.Variable.from_BNVariable(func, out_var)
- def get_parameter_var_for_incoming_var(self, in_var, func):
- in_buf = core.BNVariable()
- in_buf.type = in_var.source_type
- in_buf.index = in_var.index
- in_buf.storage = in_var.storage
+ def get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable', func:'function.Function'):
+ in_buf = in_var.to_BNVariable()
if func is None:
func_obj = None
else:
func_obj = func.handle
out_var = core.BNGetParameterVariableForIncomingVariable(self.handle, in_buf, func_obj)
- return variable.Variable(func, out_var.type, out_var.index, out_var.storage)
+ return variable.Variable.from_BNVariable(func, out_var)
@property
def arch(self):
diff --git a/python/function.py b/python/function.py
index 64aabdbb..64d54327 100644
--- a/python/function.py
+++ b/python/function.py
@@ -858,8 +858,19 @@ class Function(object):
assert v is not None, "core.BNGetStackLayout returned None"
try:
for i in range(0, count.value):
- yield variable.Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
- types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))
+ yield variable.Variable.from_BNVariable(self, v[i].var)
+ finally:
+ core.BNFreeVariableNameAndTypeList(v, count.value)
+
+ @property
+ def core_var_stack_layout(self) -> Generator['variable.CoreVariable', None, None]:
+ """List of function stack variables (read-only)"""
+ count = ctypes.c_ulonglong()
+ v = core.BNGetStackLayout(self.handle, count)
+ assert v is not None, "core.BNGetStackLayout returned None"
+ try:
+ for i in range(0, count.value):
+ yield variable.CoreVariable.from_BNVariable(v[i].var)
finally:
core.BNFreeVariableNameAndTypeList(v, count.value)
@@ -871,8 +882,19 @@ class Function(object):
assert v is not None, "core.BNGetFunctionVariables returned None"
try:
for i in range(0, count.value):
- yield variable.Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name,
- types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))
+ yield variable.Variable.from_BNVariable(self, v[i].var)
+ finally:
+ core.BNFreeVariableNameAndTypeList(v, count.value)
+
+ @property
+ def core_vars(self) -> Generator['variable.CoreVariable', None, None]:
+ """Generator of CoreVariable objects"""
+ count = ctypes.c_ulonglong()
+ v = core.BNGetFunctionVariables(self.handle, count)
+ assert v is not None, "core.BNGetFunctionVariables returned None"
+ try:
+ for i in range(0, count.value):
+ yield variable.CoreVariable.from_BNVariable(v[i].var)
finally:
core.BNFreeVariableNameAndTypeList(v, count.value)
@@ -1005,7 +1027,7 @@ class Function(object):
result = core.BNGetFunctionParameterVariables(self.handle)
var_list = []
for i in range(0, result.count):
- var_list.append(variable.Variable(self, result.vars[i].type, result.vars[i].index, result.vars[i].storage))
+ var_list.append(variable.Variable.from_BNVariable(self, result.vars[i]))
confidence = result.confidence
core.BNFreeParameterVariables(result)
return variable.ParameterVariables(var_list, confidence, self)
@@ -1919,8 +1941,8 @@ class Function(object):
result = []
for i in range(0, count.value):
var_type = types.Type(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence)
- result.append(variable.StackVariableReference(refs[i].sourceOperand, var_type,
- refs[i].name, variable.Variable.from_identifier(self, refs[i].varIdentifier, refs[i].name, var_type),
+ var = variable.Variable.from_identifier(self, refs[i].varIdentifier)
+ result.append(variable.StackVariableReference(refs[i].sourceOperand, var_type, refs[i].name, var,
refs[i].referencedOffset, refs[i].size))
core.BNFreeStackVariableReferenceList(refs, count.value)
return result
@@ -2499,46 +2521,26 @@ class Function(object):
def create_auto_var(self, var:'variable.Variable', var_type:'types.Type', name:str,
ignore_disjoint_uses:bool=False) -> None:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
tc = core.BNTypeWithConfidence()
tc.type = var_type.handle
tc.confidence = var_type.confidence
- core.BNCreateAutoVariable(self.handle, var_data, tc, name, ignore_disjoint_uses)
+ core.BNCreateAutoVariable(self.handle, var.to_BNVariable(), tc, name, ignore_disjoint_uses)
def create_user_var(self, var:'variable.Variable', var_type:'types.Type', name:str,
ignore_disjoint_uses:bool=False) -> None:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
tc = core.BNTypeWithConfidence()
tc.type = var_type.handle
tc.confidence = var_type.confidence
- core.BNCreateUserVariable(self.handle, var_data, tc, name, ignore_disjoint_uses)
+ core.BNCreateUserVariable(self.handle, var.to_BNVariable(), tc, name, ignore_disjoint_uses)
def delete_auto_var(self, var:'variable.Variable') -> None:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- core.BNDeleteAutoVariable(self.handle, var_data)
+ core.BNDeleteAutoVariable(self.handle, var.to_BNVariable())
def delete_user_var(self, var:'variable.Variable') -> None:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- core.BNDeleteUserVariable(self.handle, var_data)
+ core.BNDeleteUserVariable(self.handle, var.to_BNVariable())
def is_var_user_defined(self, var:'variable.Variable') -> bool:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- return core.BNIsVariableUserDefined(self.handle, var_data)
+ return core.BNIsVariableUserDefined(self.handle, var.to_BNVariable())
def get_stack_var_at_frame_offset(self, offset:int, addr:int, arch:Optional['architecture.Architecture']=None) -> \
Optional['variable.Variable']:
@@ -2549,9 +2551,7 @@ class Function(object):
found_var = core.BNVariableNameAndType()
if not core.BNGetStackVariableAtFrameOffset(self.handle, arch.handle, addr, offset, found_var):
return None
- result = variable.Variable(self, found_var.var.type, found_var.var.index, found_var.var.storage,
- found_var.name, types.Type(handle = core.BNNewTypeReference(found_var.type), platform = self.platform,
- confidence = found_var.typeConfidence))
+ result = variable.Variable.from_BNVariable(self, found_var.var)
core.BNFreeVariableNameAndType(found_var)
return result
@@ -2576,7 +2576,7 @@ class Function(object):
raise Exception("can not get_reg_value_at_exit if Function.arch is")
result = core.BNGetFunctionRegisterValueAtExit(self.handle, self.arch.get_reg_index(reg))
- return variable.RegisterValue(self.arch, result.value, confidence = result.confidence)
+ return variable.RegisterValue.from_BNRegisterValue(result, self.arch)
def set_auto_call_stack_adjustment(self, addr:int, adjust:Union[int, 'types.SizeWithConfidence'],\
arch:Optional['architecture.Architecture']=None) -> None:
@@ -2764,11 +2764,7 @@ class Function(object):
def_site.arch = self.arch.handle
def_site.address = def_addr
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- core.BNSetUserVariableValue(self.handle, var_data, def_site, value._to_api_object())
+ core.BNSetUserVariableValue(self.handle, var.to_BNVariable(), def_site, value._to_api_object())
def clear_user_var_value(self, var:'variable.Variable', def_addr:int) -> None:
"""
@@ -2795,11 +2791,7 @@ class Function(object):
def_site.arch = self.arch.handle
def_site.address = def_addr
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- core.BNClearUserVariableValue(self.handle, var_data, def_site)
+ core.BNClearUserVariableValue(self.handle, var.to_BNVariable(), def_site)
def get_all_user_var_values(self) -> \
Mapping['variable.Variable', Mapping['ArchAndAddr', 'variable.PossibleValueSet']]:
@@ -2816,7 +2808,7 @@ class Function(object):
i = 0
for i in range(count.value):
var_val = var_values[i]
- var = variable.Variable(self, var_val.var.type, var_val.var.index, var_val.var.storage)
+ var = variable.Variable.from_BNVariable(self, var_val.var)
if var not in result:
result[var] = {}
def_site = ArchAndAddr(var_val.defSite.arch, var_val.defSite.address)
@@ -2948,11 +2940,7 @@ class Function(object):
>>> current_function.get_mlil_var_refs(var)
"""
count = ctypes.c_ulonglong(0)
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- refs = core.BNGetMediumLevelILVariableReferences(self.handle, var_data, count)
+ refs = core.BNGetMediumLevelILVariableReferences(self.handle, var.to_BNVariable(), count)
assert refs is not None, "core.BNGetMediumLevelILVariableReferences returned None"
result = []
for i in range(0, count.value):
@@ -3002,7 +2990,7 @@ class Function(object):
refs = core.BNGetMediumLevelILVariableReferencesInRange(self.handle, arch.handle, addr, length, count)
assert refs is not None, "core.BNGetMediumLevelILVariableReferencesInRange returned None"
for i in range(0, count.value):
- var = variable.Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage)
+ var = variable.Variable.from_BNVariable(self, refs[i].var)
if refs[i].source.func:
func = Function(self.view, core.BNNewFunctionReference(refs[i].source.func))
else:
@@ -3032,11 +3020,7 @@ class Function(object):
>>> current_function.get_hlil_var_refs(var)
"""
count = ctypes.c_ulonglong(0)
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
- refs = core.BNGetHighLevelILVariableReferences(self.handle, var_data, count)
+ refs = core.BNGetHighLevelILVariableReferences(self.handle, var.to_BNVariable(), count)
assert refs is not None, "core.BNGetHighLevelILVariableReferences returned None"
result = []
for i in range(0, count.value):
@@ -3080,7 +3064,7 @@ class Function(object):
refs = core.BNGetHighLevelILVariableReferencesInRange(self.handle, arch.handle, addr, length, count)
assert refs is not None, "core.BNGetHighLevelILVariableReferencesInRange returned None"
for i in range(0, count.value):
- var = variable.Variable(self, refs[i].var.type, refs[i].var.index, refs[i].var.storage)
+ var = variable.Variable.from_BNVariable(self, refs[i].var)
if refs[i].source.func:
func = Function(self.view, core.BNNewFunctionReference(refs[i].source.func))
else:
diff --git a/python/highlevelil.py b/python/highlevelil.py
index 71c58920..831d232d 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -624,10 +624,7 @@ class HighLevelILInstruction(object):
return core.BNGetHighLevelILSSAMemoryVersionAtILInstruction(self._function.handle, self._instr_index)
def get_ssa_var_version(self, var:'variable.Variable') -> int:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
return core.BNGetHighLevelILSSAVarVersionAtILInstruction(self._function.handle, var_data, self._instr_index)
@@ -837,10 +834,7 @@ class HighLevelILFunction(object):
return core.BNGetHighLevelILNonSSAInstructionIndex(self.handle, instr)
def get_ssa_var_definition(self, ssa_var:'mediumlevelil.SSAVariable') -> Optional[HighLevelILInstruction]:
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
result = core.BNGetHighLevelILSSAVarDefinition(self.handle, var_data, ssa_var.version)
if result >= core.BNGetHighLevelILExprCount(self.handle):
return None
@@ -854,10 +848,7 @@ class HighLevelILFunction(object):
def get_ssa_var_uses(self, ssa_var:'mediumlevelil.SSAVariable') -> List[HighLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
instrs = core.BNGetHighLevelILSSAVarUses(self.handle, var_data, ssa_var.version, count)
assert instrs is not None, "core.BNGetHighLevelILSSAVarUses returned None"
result = []
@@ -884,18 +875,12 @@ class HighLevelILFunction(object):
:return: whether the variable is live at any point in the function
:rtype: bool
"""
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
return core.BNIsHighLevelILSSAVarLive(self.handle, var_data, ssa_var.version)
def get_var_definitions(self, var:'variable.Variable') -> List[HighLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
instrs = core.BNGetHighLevelILVariableDefinitions(self.handle, var_data, count)
assert instrs is not None, "core.BNGetHighLevelILVariableDefinitions returned None"
result = []
@@ -906,10 +891,7 @@ class HighLevelILFunction(object):
def get_var_uses(self, var:'variable.Variable') -> List[HighLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
instrs = core.BNGetHighLevelILVariableUses(self.handle, var_data, count)
assert instrs is not None, "core.BNGetHighLevelILVariableUses returned None"
result = []
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index 167930b6..53b5619e 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -629,10 +629,7 @@ class MediumLevelILInstruction(object):
return result
def get_ssa_var_possible_values(self, ssa_var:SSAVariable, options:List[DataFlowQueryOption]=[]):
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
option_array = (ctypes.c_int * len(options))()
idx = 0
for option in options:
@@ -645,25 +642,22 @@ class MediumLevelILInstruction(object):
return result
def get_ssa_var_version(self, var:variable.Variable) -> int:
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
return core.BNGetMediumLevelILSSAVarVersionAtILInstruction(self._function.handle, var_data, self._instr_index)
def get_var_for_reg(self, reg:'architecture.RegisterType') -> variable.Variable:
reg = self._function.arch.get_reg_index(reg)
result = core.BNGetMediumLevelILVariableForRegisterAtInstruction(self._function.handle, reg, self._instr_index)
- return variable.Variable(self._function.source_function, result.type, result.index, result.storage)
+ return variable.Variable.from_BNVariable(self._function.source_function, result)
def get_var_for_flag(self, flag:'architecture.FlagType') -> variable.Variable:
flag = self._function.arch.get_flag_index(flag)
result = core.BNGetMediumLevelILVariableForFlagAtInstruction(self._function.handle, flag, self._instr_index)
- return variable.Variable(self._function.source_function, result.type, result.index, result.storage)
+ return variable.Variable.from_BNVariable(self._function.source_function, result)
def get_var_for_stack_location(self, offset:int) -> variable.Variable:
result = core.BNGetMediumLevelILVariableForStackLocationAtInstruction(self._function.handle, offset, self._instr_index)
- return variable.Variable(self._function.source_function, result.type, result.index, result.storage)
+ return variable.Variable.from_BNVariable(self._function.source_function, result)
def get_reg_value(self, reg:'architecture.RegisterType') -> 'variable.RegisterValue':
reg = self._function.arch.get_reg_index(reg)
@@ -1113,10 +1107,7 @@ class MediumLevelILFunction(object):
return core.BNGetMediumLevelILNonSSAInstructionIndex(self.handle, instr)
def get_ssa_var_definition(self, ssa_var:SSAVariable) -> Optional[MediumLevelILInstruction]:
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
result = core.BNGetMediumLevelILSSAVarDefinition(self.handle, var_data, ssa_var.version)
if result >= core.BNGetMediumLevelILInstructionCount(self.handle):
return None
@@ -1130,10 +1121,7 @@ class MediumLevelILFunction(object):
def get_ssa_var_uses(self, ssa_var:SSAVariable) -> List[MediumLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
instrs = core.BNGetMediumLevelILSSAVarUses(self.handle, var_data, ssa_var.version, count)
assert instrs is not None, "core.BNGetMediumLevelILSSAVarUses returned None"
result = []
@@ -1160,18 +1148,12 @@ class MediumLevelILFunction(object):
:return: whether the variable is live at any point in the function
:rtype: bool
"""
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
return core.BNIsMediumLevelILSSAVarLive(self.handle, var_data, ssa_var.version)
def get_var_definitions(self, var:'variable.Variable') -> List[MediumLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
instrs = core.BNGetMediumLevelILVariableDefinitions(self.handle, var_data, count)
assert instrs is not None, "core.BNGetMediumLevelILVariableDefinitions returned None"
result = []
@@ -1182,10 +1164,7 @@ class MediumLevelILFunction(object):
def get_var_uses(self, var:'variable.Variable') -> List[MediumLevelILInstruction]:
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
instrs = core.BNGetMediumLevelILVariableDefinitions(self.handle, var_data, count)
assert instrs is not None, "core.BNGetMediumLevelILVariableDefinitions returned None"
result = []
@@ -1195,10 +1174,7 @@ class MediumLevelILFunction(object):
return result
count = ctypes.c_ulonglong()
- var_data = core.BNVariable()
- var_data.type = var.source_type
- var_data.index = var.index
- var_data.storage = var.storage
+ var_data = var.to_BNVariable()
instrs = core.BNGetMediumLevelILVariableUses(self.handle, var_data, count)
result = []
for i in range(0, count.value):
@@ -1207,10 +1183,7 @@ class MediumLevelILFunction(object):
return result
def get_ssa_var_value(self, ssa_var:SSAVariable) -> 'variable.RegisterValue':
- var_data = core.BNVariable()
- var_data.type = ssa_var.var.source_type
- var_data.index = ssa_var.var.index
- var_data.storage = ssa_var.var.storage
+ var_data = ssa_var.var.to_BNVariable()
value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version)
result = variable.RegisterValue(self._arch, value)
return result
diff --git a/python/types.py b/python/types.py
index bead9a64..3cd44bd8 100644
--- a/python/types.py
+++ b/python/types.py
@@ -19,7 +19,8 @@
# IN THE SOFTWARE.
import ctypes
-from typing import Generator, List, Union
+from typing import Generator, List, Union, Mapping, Tuple, Optional
+from dataclasses import dataclass
# Binary Ninja components
from . import _binaryninjacore as core
@@ -28,6 +29,7 @@ from . import callingconvention
from . import function
from . import variable
from . import architecture
+from . import types
from . import log
QualifiedNameType = Union[List[str], str, 'QualifiedName', List[bytes]]
@@ -588,7 +590,7 @@ class Type(object):
name = self._platform.arch.get_reg_name(params[i].location.storage)
elif params[i].location.type == VariableSourceType.StackVariableSourceType:
name = "arg_%x" % params[i].location.storage
- param_location = variable.Variable(None, params[i].location.type, params[i].location.index,
+ param_location = variable.VariableNameAndType(params[i].location.type, params[i].location.index,
params[i].location.storage, name, param_type)
result.append(FunctionParameter(param_type, params[i].name, param_location))
core.BNFreeTypeParameterList(params, count.value)
diff --git a/python/variable.py b/python/variable.py
index 187d5e3d..011402d8 100644
--- a/python/variable.py
+++ b/python/variable.py
@@ -683,21 +683,76 @@ class StackVariableReference(object):
@decorators.passive
-class Variable(object):
- def __init__(self, func, source_type, index, storage, name = None, var_type = None, identifier = None):
+@dataclass(frozen=True, order=True)
+class CoreVariable:
+ _source_type:int
+ index:int
+ storage:int
+
+ @property
+ def identifier(self) -> int:
+ return core.BNToVariableIdentifier(self.to_BNVariable())
+
+ @property
+ def source_type(self) -> VariableSourceType:
+ return VariableSourceType(self._source_type)
+
+ def to_BNVariable(self):
+ v = core.BNVariable()
+ v.type = self._source_type
+ v.index = self.index
+ v.storage = self.storage
+ return v
+
+ @classmethod
+ def from_BNVariable(cls, var:core.BNVariable):
+ return cls(var.type, var.index, var.storage)
+
+ @classmethod
+ def from_identifier(cls, identifier):
+ var = core.BNFromVariableIdentifier(identifier)
+ return cls(var.type, var.index, var.storage)
+
+@decorators.passive
+@dataclass(frozen=True, order=True)
+class VariableNameAndType(CoreVariable):
+ name:str
+ type:'binaryninja.types.Type'
+
+ @classmethod
+ def from_identifier(cls, identifier, name, type):
+ var = core.BNFromVariableIdentifier(identifier)
+ return cls(name, type, var.type, var.index, var.storage)
+
+ @classmethod
+ def from_core_variable(cls, var, name, type):
+ return cls(name, type, var.type, var.index, var.storage)
+
+
+class Variable:
+ def __init__(self, func:'binaryninja.function.Function', source_type:VariableSourceType, index:int, storage:int):
self._function = func
- self._source_type = source_type
- self._index = index
- self._storage = storage
- self._identifier = identifier
- self._name = name
- self._type = var_type
+ self._var = CoreVariable(source_type, index, storage)
+
+ @classmethod
+ def from_variable_name_and_type(cls, func:'binaryninja.function.Function', var:VariableNameAndType):
+ return cls(func, VariableSourceType(var.type), var.index, var.storage)
+
+ @classmethod
+ def from_core_variable(cls, func:'binaryninja.function.Function', var:CoreVariable):
+ return cls(func, var.source_type, var.index, var.storage)
+
+ @classmethod
+ def from_BNVariable(cls, func:'binaryninja.function.Function', var:core.BNVariable):
+ return cls(func, var.type, var.index, var.storage)
+
+ @classmethod
+ def from_identifier(cls, func:'binaryninja.function.Function', identifier:int):
+ var = core.BNFromVariableIdentifier(identifier)
+ return cls(func, VariableSourceType(var.type), var.index, var.storage)
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}>"
+ return f"<var {self.type.get_string_before_name()} {self.name}{self.type.get_string_after_name()}>"
def __str__(self):
return self.name
@@ -705,7 +760,7 @@ class Variable(object):
def __eq__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
- return (self.identifier, self.function) == (other.identifier, other.function)
+ return (self.identifier, self._function) == (other.identifier, other._function)
def __ne__(self, other):
if not isinstance(other, self.__class__):
@@ -715,108 +770,83 @@ class Variable(object):
def __lt__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
- return (self.identifier, self.function) < (other.identifier, other.function)
+ 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)
+ 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)
+ 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)
+ 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
+ return hash((self.identifier))
@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
+ return self._var.source_type
@property
def index(self) -> int:
- return self._index
-
- @index.setter
- def index(self, value:int) -> None:
- self._index = value
+ return self._var.index
@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
+ return self._var.storage
@property
def identifier(self) -> int:
- if self._identifier is None:
- self._identifier = core.BNToVariableIdentifier(self.to_BNVariable())
- return self._identifier
+ return self._var.identifier
+
+ @property
+ def core_var(self) -> CoreVariable:
+ return self._var
+
+ @property
+ def var_name_and_type(self) -> VariableNameAndType:
+ return VariableNameAndType.from_core_variable(self._var, self.name, self.type)
@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
+ return core.BNGetVariableName(self._function.handle, self._var.to_BNVariable())
+
+ @name.setter
+ def name(self, name:Optional[str]) -> None:
+ if name is None:
+ name = ""
+ self._function.create_user_var(self, self.type, 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 type(self) -> 'binaryninja.types.Type':
+ var_type_conf = core.BNGetVariableType(self._function.handle, self._var.to_BNVariable())
+ assert var_type_conf.type
+ _type = binaryninja.types.Type(var_type_conf.type, self._function.platform, var_type_conf.confidence)
+ return _type
- def to_BNVariable(self):
- v = core.BNVariable()
- v.type = self.source_type
- v.index = self._index
- v.storage = self._storage
- return v
+ @type.setter
+ def type(self, new_type:'binaryninja.types.Type') -> None:
+ self._function.create_user_var(self, new_type, self.name)
@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
+ return DeadStoreElimination(core.BNGetFunctionVariableDeadStoreElimination(self._function.handle, self._var.to_BNVariable()))
@dead_store_elimination.setter
def dead_store_elimination(self, value):
- core.BNSetFunctionVariableDeadStoreElimination(self._function.handle, self.to_BNVariable(), value)
+ core.BNSetFunctionVariableDeadStoreElimination(self._function.handle, self._var.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)
+ def to_BNVariable(self):
+ return self._var.to_BNVariable()
@decorators.passive
class ConstantReference(object):