summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py28
-rw-r--r--python/basicblock.py25
-rw-r--r--python/binaryview.py19
-rw-r--r--python/bncompleter.py8
-rw-r--r--python/demangle.py2
-rw-r--r--python/filemetadata.py2
-rw-r--r--python/highlevelil.py2
-rw-r--r--python/mediumlevelil.py2
-rw-r--r--python/plugin.py107
-rw-r--r--python/project.py2
-rw-r--r--python/variable.py31
11 files changed, 205 insertions, 23 deletions
diff --git a/python/__init__.py b/python/__init__.py
index 144d022a..9e31f906 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -94,6 +94,8 @@ if core.BNGetProduct() == "Binary Ninja Enterprise Client":
def shutdown():
"""
``shutdown`` cleanly shuts down the core, stopping all workers and closing all log files.
+
+ .. note:: This will be called automatically on script exit if you import the binaryninja module.
"""
core.BNShutdown()
@@ -103,13 +105,30 @@ atexit.register(shutdown)
@dataclass
class CoreVersionInfo:
+ """
+ Structure representing the Binary Ninja Version.
+
+ Use :py:func:`core_version_info` to look up the current version of Binary Ninja loaded.
+ """
+
major: int
+ """Major version number, e.g. 4.0.5000-dev would be 4"""
+
minor: int
+ """Minor version number, e.g. 4.0.5000-dev would be 0"""
+
build: int
+ """Build version number, e.g. 4.0.5000-dev would be 5000"""
+
channel: str
+ """Release channel name, e.g. "dev" or "Stable" """
def get_unique_identifier():
+ """
+ Generate a GUID
+ :return: A GUID string
+ """
return core.BNGetUniqueIdentifierString()
@@ -299,6 +318,10 @@ def core_set_license(licenseData: str) -> None:
def get_memory_usage_info() -> Mapping[str, int]:
+ """
+ Get counts of various Binary Ninja objects in memory.
+ :return: Dictionary of {class name: count} for objects in memory
+ """
count = ctypes.c_ulonglong()
info = core.BNGetMemoryUsageInfo(count)
assert info is not None, "core.BNGetMemoryUsageInfo returned None"
@@ -341,7 +364,7 @@ def load(*args, **kwargs) -> BinaryView:
return bv
-@deprecation.deprecated(deprecated_in="3.5.4378", details='Use :py:func:`BinaryView.load` instead')
+@deprecation.deprecated(deprecated_in="3.5.4378", details='Use :py:func:`load` instead')
def open_view(*args, **kwargs) -> BinaryView:
return load(*args, **kwargs)
@@ -383,6 +406,9 @@ def connect_vscode_debugger(port=5678):
class UIPluginInHeadlessError(Exception):
+ """
+ Error thrown when trying to load a UI plugin in a headless Binary Ninja installation.
+ """
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args, **kwargs)
diff --git a/python/basicblock.py b/python/basicblock.py
index a22b540f..6c03fe32 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -33,6 +33,18 @@ from . import function as _function
@dataclass(frozen=True)
class BasicBlockEdge:
+ """
+ ``class BasicBlockEdge`` represents the edges that connect basic blocks in graph view.
+
+ :cvar type: The :py:meth:`enums.BranchType` of the edge; Whether the edge is a true branch, false branch, unconditional, etc.
+ :cvar source: The basic block that the edge originates from.
+ :cvar target: The basic block that the edge is going to.
+ :cvar backedge: Whether this edge targets to a node whose control flow can eventually flow back through the source node of this edge.
+ :Example:
+
+ >>> current_basic_block.outgoing_edges
+ [<TrueBranch: x86_64@0x6>, <FalseBranch: x86_64@0x1f>]
+ """
type: BranchType
source: 'BasicBlock'
target: 'BasicBlock'
@@ -50,7 +62,18 @@ class BasicBlockEdge:
class BasicBlock:
"""
- The ``BasicBlock`` object is returned during analysis and should not be directly instantiated.
+ The ``class BasicBlock`` object is returned during analysis and should not be directly instantiated.
+
+ Basic blocks contain a sequence of instructions that must execute in-order with no branches.
+ We include calls in basic blocks, which technically violates that assumption, but you can mark
+ functions as `func.can_return = False` if a given function should terminate basic blocks.
+ :Example:
+
+ >>> for func in bv.functions:
+ >>> for bb in func:
+ >>> # Any block-based analysis could start here
+ >>> for inst in bb:
+ >>> pass # Optionally do something here with instructions
"""
def __init__(self, handle: core.BNBasicBlockHandle, view: Optional['binaryview.BinaryView'] = None):
self._view = view
diff --git a/python/binaryview.py b/python/binaryview.py
index ec8475c8..aaad9b0f 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -455,7 +455,7 @@ class AnalysisCompletionEvent:
"""
The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving
callbacks when analysis is complete. The callback runs once. A completion event must be added
- for each new analysis in order to be notified of each analysis completion. The
+ for each new analysis in order to be notified of each analysis completion. The
AnalysisCompletionEvent class takes responsibility for keeping track of the object's lifetime.
:Example:
@@ -2019,7 +2019,7 @@ class BinaryView:
either and are used explicitly for subclassing a BinaryView.
.. note:: An important note on the ``*_user_*()`` methods. Binary Ninja makes a distinction between edits \
- performed by the user and actions performed by auto analysis. Auto analysis actions that can quickly be recalculated \
+ performed by the user and actions performed by auto analysis. Auto analysis actions that can quickly be recalculated \
are not saved to the database. Auto analysis actions that take a long time and all user edits are stored in the \
database (e.g. :py:func:`remove_user_function` rather than :py:func:`remove_function`). Thus use ``_user_`` methods if saving \
to the database is desired.
@@ -3752,7 +3752,7 @@ class BinaryView:
"""
``read`` returns the data reads at most ``length`` bytes from virtual address ``addr``.
- .. note:: Python2 returns a str, but Python3 returns a bytes object. str(DataBufferObject) will \
+ .. note:: Python2 returns a str, but Python3 returns a bytes object. str(DataBufferObject) will \
still get you a str in either case.
:param int addr: virtual address to read from.
@@ -4184,10 +4184,9 @@ class BinaryView:
def update_analysis(self) -> None:
"""
- ``update_analysis`` asynchronously starts the analysis running and returns immediately. Analysis of BinaryViews
- does not occur automatically, the user must start analysis by calling either :py:func:`update_analysis` or
- :py:func:`update_analysis_and_wait`. An analysis update **must** be run after changes are made which could change
- analysis results such as adding functions.
+ ``update_analysis`` asynchronously starts the analysis running and returns immediately.
+ An analysis update **must** be run after changes are made which could change analysis
+ results such as adding functions.
:rtype: None
"""
@@ -4196,9 +4195,7 @@ class BinaryView:
def update_analysis_and_wait(self) -> None:
"""
``update_analysis_and_wait`` blocking call to update the analysis, this call returns when the analysis is
- complete. Analysis of BinaryViews does not occur automatically, the user must start analysis by calling either
- :py:func:`update_analysis` or :py:func:`update_analysis_and_wait`. An analysis update **must** be run after changes are
- made which could change analysis results such as adding functions.
+ complete. An analysis update **must** be run after changes are made which could change analysis results such as adding functions.
:rtype: None
"""
@@ -6202,7 +6199,7 @@ class BinaryView:
) -> bool:
"""
``is_skip_and_return_zero_patch_available`` queries the architecture plugin to determine if the
- instruction at ``addr`` is similar to an x86 "call" instruction which can be made to return zero. The actual
+ instruction at ``addr`` is similar to an x86 "call" instruction which can be made to return zero. The actual
logic of which is implemented in the ``perform_is_skip_and_return_zero_patch_available`` in the corresponding
architecture.
diff --git a/python/bncompleter.py b/python/bncompleter.py
index 9a33659b..3b632aab 100644
--- a/python/bncompleter.py
+++ b/python/bncompleter.py
@@ -25,14 +25,14 @@ Tip: to use the tab key as the completion key, call
Notes:
- Exceptions raised by the completer function are *ignored* (and generally cause
- the completion to fail). This is a feature -- since readline sets the tty
+ the completion to fail). This is a feature -- since readline sets the tty
device in raw (or cbreak) mode, printing a traceback wouldn't work well
without some complicated hoopla to save, reset and restore the tty state.
- The evaluation of the NAME.NAME... form may cause arbitrary application
defined code to be executed if an object with a __getattr__ hook is found.
Since it is the responsibility of the application (or the user) to enable this
- feature, I consider this an acceptable risk. More complicated expressions
+ feature, I consider this an acceptable risk. More complicated expressions
(e.g. function calls or indexing operations) are *not* evaluated.
- When the original stdin is not a tty device, GNU readline is never
@@ -89,7 +89,7 @@ class Completer:
"""Return the next possible completion for 'text'.
This is called successively with state == 0, 1, 2, ... until it
- returns None. The completion should begin with 'text'.
+ returns None. The completion should begin with 'text'.
"""
if self.use_main_ns:
@@ -152,7 +152,7 @@ class Completer:
Assuming the text is of the form NAME.NAME....[NAME], and is
evaluable in self.namespace, it will be evaluated and its attributes
- (as revealed by dir()) are used as possible completions. (For class
+ (as revealed by dir()) are used as possible completions. (For class
instances, class members are also considered.)
WARNING: this can still invoke arbitrary C code, if an object
diff --git a/python/demangle.py b/python/demangle.py
index 89532f78..874b13cf 100644
--- a/python/demangle.py
+++ b/python/demangle.py
@@ -158,7 +158,7 @@ def simplify_name_to_string(input_name):
def simplify_name_to_qualified_name(input_name, simplify=True):
"""
- ``simplify_name_to_qualified_name`` simplifies a templated C++ name with default arguments and returns a qualified name. This can also tokenize a string to a qualified name with/without simplifying it
+ ``simplify_name_to_qualified_name`` simplifies a templated C++ name with default arguments and returns a qualified name. This can also tokenize a string to a qualified name with/without simplifying it
:param input_name: String or qualified name to be simplified
:type input_name: Union[str, QualifiedName]
diff --git a/python/filemetadata.py b/python/filemetadata.py
index e51436b1..4dbde1a7 100644
--- a/python/filemetadata.py
+++ b/python/filemetadata.py
@@ -519,7 +519,7 @@ class FileMetadata:
"""
``navigate`` navigates the UI to the specified virtual address
- .. note:: Despite the confusing name, ``view`` in this context is not a BinaryView but rather a string describing the different UI Views. Check :py:attr:`view` while in different views to see examples such as ``Linear:ELF``, ``Graph:PE``.
+ .. note:: Despite the confusing name, ``view`` in this context is not a BinaryView but rather a string describing the different UI Views. Check :py:attr:`view` while in different views to see examples such as ``Linear:ELF``, ``Graph:PE``.
:param str view: view name
:param int offset: address to navigate to
diff --git a/python/highlevelil.py b/python/highlevelil.py
index da1d9346..ff35c018 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -2888,7 +2888,7 @@ class HighLevelILFunction:
@property
def aliased_vars(self) -> List["variable.Variable"]:
- """This returns a list of Variables that are taken reference to and used elsewhere. You may also wish to consider `HighLevelIlFunction.vars` and `HighLevelIlFunction.source_function.parameter_vars`"""
+ """This returns a list of Variables that are taken reference to and used elsewhere. You may also wish to consider `HighLevelIlFunction.vars` and `HighLevelIlFunction.source_function.parameter_vars`"""
if self.source_function is None:
return []
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index e8e020ea..db5da1a1 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -3710,7 +3710,7 @@ class MediumLevelILFunction:
@property
def aliased_vars(self) -> List["variable.Variable"]:
- """This returns a list of Variables that are taken reference to and used elsewhere. You may also wish to consider `MediumLevelIlFunction.vars` and `MediumLevelIlFunction.source_function.parameter_vars`"""
+ """This returns a list of Variables that are taken reference to and used elsewhere. You may also wish to consider `MediumLevelIlFunction.vars` and `MediumLevelIlFunction.source_function.parameter_vars`"""
if self.source_function is None:
return []
diff --git a/python/plugin.py b/python/plugin.py
index 4d65db0b..455d511e 100644
--- a/python/plugin.py
+++ b/python/plugin.py
@@ -103,6 +103,13 @@ class _PluginCommandMetaClass(type):
class PluginCommand(metaclass=_PluginCommandMetaClass):
+ """
+ The ``class PluginCommand` contains all the plugin registration methods as class methods.
+
+ You shouldn't need to create an instance of this class, instead see `register`,
+ `register_for_address`, `register_for_function`, and similar class methods for examples
+ on how to register your plugin.
+ """
_registered_commands = []
def __init__(self, cmd):
@@ -369,6 +376,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` as an argument
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView):
+ >>> log_info(f"My plugin was called on bv: `{bv}`")
+ >>> PluginCommand.register("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView) -> bool:
+ >>> return False
+ >>> PluginCommand.register("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -395,6 +412,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and address as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and address to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, address: int):
+ >>> log_info(f"My plugin was called on bv: `{bv}` at address {hex(address)}")
+ >>> PluginCommand.register_for_address("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, address: int) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_address("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_address`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -421,6 +448,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView`, start address, and length as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView`, start address, and length to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, start: int, length: int):
+ >>> log_info(f"My plugin was called on bv: `{bv}` at {hex(start)} of length {hex(length)}")
+ >>> PluginCommand.register_for_range("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, start: int, length: int) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_range("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_range`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -447,6 +484,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~function.Function` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~function.Function` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, func: Function):
+ >>> log_info(f"My plugin was called on func {func} in bv `{bv}`")
+ >>> PluginCommand.register_for_function("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, func: Function) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_function("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -474,6 +521,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~lowlevelil.LowLevelILFunction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~lowlevelil.LowLevelILFunction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, func: LowLevelILFunction):
+ >>> log_info(f"My plugin was called on func {func} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, func: LowLevelILFunction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -502,6 +559,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~lowlevelil.LowLevelILInstruction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~lowlevelil.LowLevelILInstruction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, inst: LowLevelILInstruction):
+ >>> log_info(f"My plugin was called on inst {inst} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, inst: LowLevelILInstruction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -531,6 +598,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~mediumlevelil.MediumLevelILFunction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~mediumlevelil.MediumLevelILFunction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, func: MediumLevelILFunction):
+ >>> log_info(f"My plugin was called on func {func} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, func: MediumLevelILFunction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -559,6 +636,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~mediumlevelil.MediumLevelILInstruction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~mediumlevelil.MediumLevelILInstruction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, inst: MediumLevelILInstruction):
+ >>> log_info(f"My plugin was called on inst {inst} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, inst: MediumLevelILInstruction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -588,6 +675,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~highlevelil.HighLevelILFunction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~highlevelil.HighLevelILFunction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, func: HighLevelILFunction):
+ >>> log_info(f"My plugin was called on func {func} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, func: HighLevelILFunction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_function("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_high_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
@@ -616,6 +713,16 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
:param callback action: function to call with the :class:`~binaryview.BinaryView` and a :class:`~highlevelil.HighLevelILInstruction` as arguments
:param callback is_valid: optional argument of a function passed a :class:`~binaryview.BinaryView` and :class:`~highlevelil.HighLevelILInstruction` to determine whether the plugin should be enabled for that view
:rtype: None
+ :Example:
+
+ >>> def my_plugin(bv: BinaryView, inst: HighLevelILInstruction):
+ >>> log_info(f"My plugin was called on inst {inst} in bv `{bv}`")
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin", "My plugin description (not used)", my_plugin)
+ True
+ >>> def is_valid(bv: BinaryView, inst: HighLevelILInstruction) -> bool:
+ >>> return False
+ >>> PluginCommand.register_for_low_level_il_instruction("My Plugin (With Valid Function)", "My plugin description (not used)", my_plugin, is_valid)
+ True
.. warning:: Calling ``register_for_high_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin.
"""
diff --git a/python/project.py b/python/project.py
index d9b9880d..a080123a 100644
--- a/python/project.py
+++ b/python/project.py
@@ -664,7 +664,7 @@ class Project:
and the project on disk vs in memory may not agree on state
if an exception occurs while a bulk operation is happening.
- :example:
+ :Example:
>>> from pathlib import Path
>>> with project.bulk_operation():
... for i in Path('/bin/').iterdir():
diff --git a/python/variable.py b/python/variable.py
index 0a86b850..75e95712 100644
--- a/python/variable.py
+++ b/python/variable.py
@@ -644,16 +644,28 @@ class StackVariableReference:
@dataclass(frozen=True, order=True)
class CoreVariable:
+ """
+ ``class CoreVariable`` is the base class for other variable types,
+ such as :py:meth:`VariableNameAndType` and :py:meth:`Variable`
+
+ :cvar index: Internal identifier
+ :cvar storage: If this variable is a stack variable
+ (`source_type == VariableSourceType.StackVariableSourceType`),
+ then the storage location is the offset onto the stack that contains
+ the first byte of this variable. Otherwise it's used as an internal identifier.
+ """
_source_type: int
index: int
storage: int
@property
def identifier(self) -> int:
+ """A UID for a variable within a function."""
return core.BNToVariableIdentifier(self.to_BNVariable())
@property
def source_type(self) -> VariableSourceType:
+ """Whether this variable was created based off of an underlying register, stack location, or flag."""
return VariableSourceType(self._source_type)
def to_BNVariable(self):
@@ -675,6 +687,16 @@ class CoreVariable:
@dataclass(frozen=True, order=True)
class VariableNameAndType(CoreVariable):
+ """
+ ``class VariableNameAndType`` is a lightweight wrapper around a
+ variable and its name, useful for shuttling between APIs that require
+ them both. While :py:meth:`Variable` has :py:meth:`Variable.name` and
+ :py:meth:`Variable.type` fields, those require additional core calls
+ each time you fetch them.
+
+ :cvar name: The variable's name
+ :cvar type: The variable's type
+ """
name: str
type: 'binaryninja.types.Type'
@@ -689,6 +711,10 @@ class VariableNameAndType(CoreVariable):
class Variable(CoreVariable):
+ """
+ ``class Variable`` represents variables in Binary Ninja. Variables are resolved
+ in medium level IL, so variables objects are only valid for MLIL and above.
+ """
def __init__(self, func: FunctionOrILFunction, source_type: VariableSourceType, index: int, storage: int):
super(Variable, self).__init__(int(source_type), index, storage)
if isinstance(func, binaryninja.function.Function):
@@ -759,10 +785,12 @@ class Variable(CoreVariable):
@property
def core_variable(self) -> CoreVariable:
+ """Retrieve the underlying :py:meth:`CoreVariable` class"""
return CoreVariable(self._source_type, self.index, self.storage)
@property
def var_name_and_type(self) -> VariableNameAndType:
+ """Convert to :py:meth:`VariableNameAndType` """
return VariableNameAndType.from_core_variable(self, self.name, self.type)
@property
@@ -794,7 +822,7 @@ class Variable(CoreVariable):
@property
def ssa_versions(self) -> Generator[int, None, None]:
- """Returns the SSA versions associated with this variable. Doesn't return anything for aliased variables."""
+ """Returns the SSA versions associated with this variable. Doesn't return anything for aliased variables."""
if self._il_function is None:
raise NotImplementedError("No IL function associated with variable")
@@ -825,6 +853,7 @@ class Variable(CoreVariable):
@property
def dead_store_elimination(self) -> DeadStoreElimination:
+ """returns the dead store elimination setting for this variable"""
return DeadStoreElimination(
core.BNGetFunctionVariableDeadStoreElimination(self._function.handle, self.to_BNVariable())
)