diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/callingconvention.py | 54 | ||||
| -rw-r--r-- | python/function.py | 102 | ||||
| -rw-r--r-- | python/highlevelil.py | 30 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 51 | ||||
| -rw-r--r-- | python/types.py | 6 | ||||
| -rw-r--r-- | python/variable.py | 178 |
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): |
