diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/function.py | 58 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 22 | ||||
| -rw-r--r-- | python/variable.py | 9 |
3 files changed, 87 insertions, 2 deletions
diff --git a/python/function.py b/python/function.py index 9a0f099a..d2855234 100644 --- a/python/function.py +++ b/python/function.py @@ -1377,6 +1377,26 @@ class Function: return None return flowgraph.CoreFlowGraph(graph) + @property + def merged_vars(self) -> Dict['variable.Variable', List['variable.Variable']]: + """ + Map of merged variables, organized by target variable (read-only). Use ``merge_vars`` and + ``unmerge_vars`` to update merged variables. + """ + count = ctypes.c_ulonglong() + data = core.BNGetMergedVariables(self.handle, count) + + result = {} + for i in range(count.value): + target = Variable.from_BNVariable(self, data[i].target) + sources = [] + for j in range(data[i].sourceCount): + sources.append(Variable.from_BNVariable(self, data[i].sources[j])) + result[target] = sources + + core.BNFreeMergedVariableList(data, count.value) + return result + def mark_recent_use(self) -> None: core.BNMarkFunctionAsRecentlyUsed(self.handle) @@ -3316,6 +3336,44 @@ class Function: return start.value return None + def merge_vars( + self, target: 'variable.Variable', sources: Union[List['variable.Variable'], 'variable.Variable'] + ) -> None: + """ + ``merge_vars`` merges one or more varibles in ``sources`` into the ``target`` variable. All + variable accesses to the variables in ``sources`` will be rewritten to use ``target``. + + :param Variable target: target variable + :param list(Variable) sources: list of source variables + """ + if isinstance(sources, variable.Variable): + sources = [sources] + source_list = (core.BNVariable * len(sources))() + for i in range(0, len(sources)): + source_list[i].type = sources[i].source_type + source_list[i].index = sources[i].index + source_list[i].storage = sources[i].storage + core.BNMergeVariables(self.handle, target.to_BNVariable(), source_list, len(sources)) + + def unmerge_vars( + self, target: 'variable.Variable', sources: Union[List['variable.Variable'], 'variable.Variable'] + ) -> None: + """ + ``unmerge_vars`` undoes variable merging performed with ``merge_vars``. The variables in + ``sources`` will no longer be merged into the ``target`` variable. + + :param Variable target: target variable + :param list(Variable) sources: list of source variables + """ + if isinstance(sources, variable.Variable): + sources = [sources] + source_list = (core.BNVariable * len(sources))() + for i in range(0, len(sources)): + source_list[i].type = sources[i].source_type + source_list[i].index = sources[i].index + source_list[i].storage = sources[i].storage + core.BNUnmergeVariables(self.handle, target.to_BNVariable(), source_list, len(sources)) + class AdvancedFunctionAnalysisDataRequestor: def __init__(self, func: 'Function' = None): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 07ca7a22..ceb33f50 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -3024,6 +3024,28 @@ class MediumLevelILFunction: finally: core.BNFreeILInstructionList(instrs) + def get_live_instructions_for_var(self, var: 'variable.Variable', include_last_use: bool = True) -> List[MediumLevelILInstruction]: + """ + ``get_live_instructions_for_var`` computes the list of instructions for which ``var`` is live. + If ``include_last_use`` is False, the last use of the variable will not be included in the + list (this allows for easier computation of overlaps in liveness between two variables). + If the variable is never used, this function will return an empty list. + + :param SSAVariable var: the variable to query + :param bool include_last_use: whether to include the last use of the variable in the list of instructions + :return: list of instructions for which ``var`` is live + :rtype: list(MediumLevelILInstruction) + """ + count = ctypes.c_ulonglong() + var_data = var.to_BNVariable() + instrs = core.BNGetMediumLevelILLiveInstructionsForVariable(self.handle, var_data, include_last_use, count) + assert instrs is not None, "core.BNGetMediumLevelILLiveInstructionsForVariable returned None" + result = [] + for i in range(0, count.value): + result.append(self[instrs[i]]) + core.BNFreeILInstructionList(instrs) + return result + def get_ssa_var_value(self, ssa_var: SSAVariable) -> 'variable.RegisterValue': var_data = ssa_var.var.to_BNVariable() value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version) diff --git a/python/variable.py b/python/variable.py index 07b8863c..839e87ce 100644 --- a/python/variable.py +++ b/python/variable.py @@ -663,7 +663,7 @@ class Variable(CoreVariable): 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 repr(super()) + return f"<var {self.name}>" def __str__(self): return self.name @@ -712,7 +712,7 @@ class Variable(CoreVariable): @property def name(self) -> str: """Name of the variable, Settings thisslow because it ensures that analysis has been updated. """ - return core.BNGetRealVariableName(self._function.handle, self._function.arch.handle, self.to_BNVariable()) + return core.BNGetVariableNameOrDefault(self._function.handle, self.to_BNVariable()) @name.setter def name(self, name: Optional[str]) -> None: @@ -720,6 +720,11 @@ class Variable(CoreVariable): self._function.view.update_analysis_and_wait() @property + def last_seen_name(self) -> str: + """Name of the variable, or the name most recently assigned if the variable has since been removed (read-only). """ + return core.BNGetLastSeenVariableNameOrDefault(self._function.handle, self.to_BNVariable()) + + @property def type(self) -> Optional['binaryninja.types.Type']: var_type_conf = core.BNGetVariableType(self._function.handle, self.to_BNVariable()) if var_type_conf.type: |
