From 6812c973c9fa9b4ad642ab81856c05f87bd6fcc4 Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Thu, 27 Jan 2022 22:43:28 -0500 Subject: Format All Files --- python/__init__.py | 32 +- python/architecture.py | 515 ++++++---- python/associateddatastore.py | 9 +- python/basicblock.py | 60 +- python/binaryview.py | 1368 ++++++++++++++----------- python/bncompleter.py | 20 +- python/callingconvention.py | 119 ++- python/commonil.py | 5 +- python/compatibility.py | 3 +- python/database.py | 612 ++++++------ python/databuffer.py | 14 +- python/dataclasses.py | 1538 ++++++++++++++--------------- python/datarender.py | 19 +- python/debuginfo.py | 84 +- python/decorators.py | 1 - python/demangle.py | 40 +- python/downloadprovider.py | 43 +- python/enterprise.py | 6 +- python/examples/angr_plugin.py | 27 +- python/examples/arch_hook.py | 17 +- python/examples/asm_to_llil_view.py | 15 +- python/examples/breakpoint.py | 8 +- python/examples/cli_dis.py | 5 +- python/examples/cli_lift.py | 21 +- python/examples/debug_info.py | 157 +-- python/examples/export_svg.py | 343 +++---- python/examples/helloglobalarea.py | 2 + python/examples/hellopane.py | 7 +- python/examples/hellosidebar.py | 3 + python/examples/instruction_iterator.py | 3 - python/examples/jump_table.py | 6 +- python/examples/linear_mlil.py | 47 +- python/examples/mappedview.py | 27 +- python/examples/nds.py | 146 +-- python/examples/nes.py | 552 ++++++----- python/examples/notification_callbacks.py | 2 + python/examples/nsf.py | 9 +- python/examples/pe_stat.py | 7 +- python/examples/print_syscalls.py | 4 +- python/examples/typelib_create.py | 29 +- python/examples/typelib_dump.py | 197 ++-- python/examples/ui_notifications.py | 102 +- python/fileaccessor.py | 3 +- python/filemetadata.py | 103 +- python/flowgraph.py | 58 +- python/function.py | 816 ++++++++------- python/functionrecognizer.py | 16 +- python/generator.cpp | 129 +-- python/highlevelil.py | 830 ++++++++-------- python/highlight.py | 15 +- python/interaction.py | 84 +- python/lineardisassembly.py | 117 ++- python/log.py | 4 +- python/lowlevelil.py | 1424 +++++++++++++------------- python/mediumlevelil.py | 1093 ++++++++++---------- python/metadata.py | 9 +- python/platform.py | 73 +- python/plugin.py | 337 ++++--- python/pluginmanager.py | 7 +- python/scriptingprovider.py | 164 +-- python/settings.py | 50 +- python/transform.py | 18 +- python/typelibrary.py | 5 +- python/types.py | 902 ++++++++++------- python/update.py | 11 +- python/variable.py | 192 ++-- python/websocketprovider.py | 19 +- python/workflow.py | 55 +- 68 files changed, 6992 insertions(+), 5766 deletions(-) (limited to 'python') diff --git a/python/__init__.py b/python/__init__.py index 9f193bea..b973118a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - import atexit import sys import ctypes @@ -26,7 +25,6 @@ from time import gmtime, struct_time import os from typing import Mapping, Optional - # Binary Ninja components import binaryninja._binaryninjacore as core import binaryninja @@ -68,9 +66,10 @@ from .commonil import * from .database import * # We import each of these by name to prevent conflicts between # log.py and the function 'log' which we don't import below -from .log import (redirect_output_to_log, is_output_redirected_to_log, - log_debug, log_info, log_warn, log_error, log_alert, - log_to_stdout, log_to_stderr, log_to_file, close_logs) +from .log import ( + redirect_output_to_log, is_output_redirected_to_log, log_debug, log_info, log_warn, log_error, log_alert, + log_to_stdout, log_to_stderr, log_to_file, close_logs +) from .log import log as log_at_level # Only load Enterprise Client support on Enterprise builds if core.BNGetProduct() == "Binary Ninja Enterprise Client": @@ -136,15 +135,17 @@ def _init_plugins(): pass if not core.BNIsLicenseValidated() or not enterprise.is_license_still_activated(): raise RuntimeError( - "To use Binary Ninja Enterprise from a headless python script, you must check out a license first.\n" - "You can either check out a license for an extended time with the UI, or use the binaryninja.enterprise module.") + "To use Binary Ninja Enterprise from a headless python script, you must check out a license first.\n" + "You can either check out a license for an extended time with the UI, or use the binaryninja.enterprise module." + ) if not _plugin_init: # The first call to BNInitCorePlugins returns True for successful initialization and True in this context indicates headless operation. # The result is pulled from BNInitPlugins as that now wraps BNInitCorePlugins. is_headless_init_once = core.BNInitPlugins(not os.environ.get('BN_DISABLE_USER_PLUGINS')) min_level = Settings().get_string("python.log.minLevel") - if _enable_default_log and is_headless_init_once and min_level in LogLevel.__members__ and not core_ui_enabled() and sys.stderr.isatty(): + if _enable_default_log and is_headless_init_once and min_level in LogLevel.__members__ and not core_ui_enabled( + ) and sys.stderr.isatty(): log_to_stderr(LogLevel[min_level]) core.BNInitRepoPlugins() if core.BNIsLicenseValidated(): @@ -162,6 +163,7 @@ def disable_default_log() -> None: _enable_default_log = False close_logs() + def bundled_plugin_path() -> Optional[str]: """ ``bundled_plugin_path`` returns a string containing the current plugin path inside the `install path `_ @@ -171,6 +173,7 @@ def bundled_plugin_path() -> Optional[str]: """ return core.BNGetBundledPluginDirectory() + def user_plugin_path() -> Optional[str]: """ ``user_plugin_path`` returns a string containing the current plugin path inside the `user directory `_ @@ -180,6 +183,7 @@ def user_plugin_path() -> Optional[str]: """ return core.BNGetUserPluginDirectory() + def user_directory() -> Optional[str]: """ ``user_directory`` returns a string containing the path to the `user directory `_ @@ -189,6 +193,7 @@ def user_directory() -> Optional[str]: """ return core.BNGetUserDirectory() + def core_version() -> Optional[str]: """ ``core_version`` returns a string containing the current version @@ -198,6 +203,7 @@ def core_version() -> Optional[str]: """ return core.BNGetVersionString() + def core_build_id() -> int: """ ``core_build_id`` returns a integer containing the current build id @@ -207,6 +213,7 @@ def core_build_id() -> int: """ return core.BNGetBuildId() + def core_serial() -> Optional[str]: """ ``core_serial`` returns a string containing the current serial number @@ -216,28 +223,33 @@ def core_serial() -> Optional[str]: """ return core.BNGetSerialNumber() + def core_expires() -> struct_time: '''License Expiration''' return gmtime(core.BNGetLicenseExpirationTime()) + def core_product() -> Optional[str]: '''Product string from the license file''' return core.BNGetProduct() + def core_product_type() -> Optional[str]: '''Product type from the license file''' return core.BNGetProductType() + def core_license_count() -> int: '''License count from the license file''' return core.BNGetLicenseCount() + def core_ui_enabled() -> bool: '''Indicates that a UI exists and the UI has invoked BNInitUI''' return core.BNIsUIEnabled() -def core_set_license(licenseData:str) -> None: +def core_set_license(licenseData: str) -> None: ''' ``core_set_license`` is used to initialize the core with a license file that doesn't necessarily reside on a file system. This is especially useful for headless environments such as docker where loading the license file via an environment variable allows for greater security of the license file itself. @@ -294,7 +306,7 @@ def connect_pycharm_debugger(port=5678): # Get pip install string from PyCharm's Python Debug Server Configuration # e.g. for PyCharm 2021.1.1 #PY-7142.13: # pip install --user pydevd-pycharm~=211.7142.13 - import pydevd_pycharm # type: ignore + import pydevd_pycharm # type: ignore pydevd_pycharm.settrace('localhost', port=port, stdoutToServer=True, stderrToServer=True, suspend=False) diff --git a/python/architecture.py b/python/architecture.py index fd9e28f1..ff598a35 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -26,9 +26,10 @@ from dataclasses import dataclass, field # Binary Ninja components import binaryninja from . import _binaryninjacore as core -from .enums import (Endianness, ImplicitRegisterExtend, BranchType, - LowLevelILFlagCondition, FlagRole, LowLevelILOperation, - InstructionTextTokenType, InstructionTextTokenContext) +from .enums import ( + Endianness, ImplicitRegisterExtend, BranchType, LowLevelILFlagCondition, FlagRole, LowLevelILOperation, + InstructionTextTokenType, InstructionTextTokenContext +) from .log import log_error from . import lowlevelil from . import types @@ -65,11 +66,11 @@ IntrinsicType = Union[IntrinsicName, 'lowlevelil.ILIntrinsic', IntrinsicIndex] @dataclass(frozen=True) class RegisterInfo: - full_width_reg:RegisterName - size:int - offset:int = 0 - extend:ImplicitRegisterExtend = ImplicitRegisterExtend.NoExtend - index:Optional[RegisterIndex] = None + full_width_reg: RegisterName + size: int + offset: int = 0 + extend: ImplicitRegisterExtend = ImplicitRegisterExtend.NoExtend + index: Optional[RegisterIndex] = None def __repr__(self): if self.extend == ImplicitRegisterExtend.ZeroExtendToFullWidth: @@ -83,10 +84,10 @@ class RegisterInfo: @dataclass(frozen=True) class RegisterStackInfo: - storage_regs:List[RegisterName] - top_relative_regs:List[RegisterName] - stack_top_reg:RegisterName - index:Optional[RegisterStackIndex] = None + storage_regs: List[RegisterName] + top_relative_regs: List[RegisterName] + stack_top_reg: RegisterName + index: Optional[RegisterStackIndex] = None def __repr__(self): return f"" @@ -94,8 +95,8 @@ class RegisterStackInfo: @dataclass(frozen=True) class IntrinsicInput: - type:'types.Type' - name:str = "" + type: 'types.Type' + name: str = "" def __repr__(self): if len(self.name) == 0: @@ -105,9 +106,9 @@ class IntrinsicInput: @dataclass(frozen=True) class IntrinsicInfo: - inputs:List[IntrinsicInput] - outputs:List['types.Type'] - index:Optional[int] = None + inputs: List[IntrinsicInput] + outputs: List['types.Type'] + index: Optional[int] = None def __repr__(self): return f" {repr(self.outputs)}>" @@ -115,9 +116,9 @@ class IntrinsicInfo: @dataclass(frozen=True) class InstructionBranch: - type:BranchType - target:int - arch:Optional['Architecture'] + type: BranchType + target: int + arch: Optional['Architecture'] def __repr__(self): if self.arch is not None: @@ -127,12 +128,12 @@ class InstructionBranch: @dataclass(frozen=False) class InstructionInfo: - length:int = 0 - arch_transition_by_target_addr:bool = False - branch_delay:bool = False - branches:List[InstructionBranch] = field(default_factory=list) + length: int = 0 + arch_transition_by_target_addr: bool = False + branch_delay: bool = False + branches: List[InstructionBranch] = field(default_factory=list) - def add_branch(self, branch_type:BranchType, target:int = 0, arch:Optional['Architecture'] = None) -> None: + def add_branch(self, branch_type: BranchType, target: int = 0, arch: Optional['Architecture'] = None) -> None: self.branches.append(InstructionBranch(branch_type, target, arch)) def __len__(self): @@ -158,7 +159,7 @@ class _ArchitectureMetaClass(type): finally: core.BNFreeArchitectureList(archs) - def __getitem__(cls:'_ArchitectureMetaClass', name:str) -> 'Architecture': + def __getitem__(cls: '_ArchitectureMetaClass', name: str) -> 'Architecture': binaryninja._init_plugins() arch = core.BNGetArchitectureByName(name) if arch is None: @@ -207,7 +208,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): global_regs = [] system_regs = [] flags = [] - flag_write_types:List[FlagWriteTypeName] = [] + flag_write_types: List[FlagWriteTypeName] = [] semantic_flag_classes = [] semantic_flag_groups = [] flag_roles = {} @@ -235,47 +236,63 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) - self._cb.getAssociatedArchitectureByAddress = \ - self._cb.getAssociatedArchitectureByAddress.__class__(self._get_associated_arch_by_address) + self._cb.getAssociatedArchitectureByAddress = self._cb.getAssociatedArchitectureByAddress.__class__( + self._get_associated_arch_by_address + ) self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info) self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text) self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text) self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__( - self._get_instruction_low_level_il) + self._get_instruction_low_level_il + ) self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) - self._cb.getSemanticFlagClassName = self._cb.getSemanticFlagClassName.__class__(self._get_semantic_flag_class_name) - self._cb.getSemanticFlagGroupName = self._cb.getSemanticFlagGroupName.__class__(self._get_semantic_flag_group_name) + self._cb.getSemanticFlagClassName = self._cb.getSemanticFlagClassName.__class__( + self._get_semantic_flag_class_name + ) + self._cb.getSemanticFlagGroupName = self._cb.getSemanticFlagGroupName.__class__( + self._get_semantic_flag_group_name + ) self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers) self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers) self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags) self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types) - self._cb.getAllSemanticFlagClasses = self._cb.getAllSemanticFlagClasses.__class__(self._get_all_semantic_flag_classes) - self._cb.getAllSemanticFlagGroups = self._cb.getAllSemanticFlagGroups.__class__(self._get_all_semantic_flag_groups) + self._cb.getAllSemanticFlagClasses = self._cb.getAllSemanticFlagClasses.__class__( + self._get_all_semantic_flag_classes + ) + self._cb.getAllSemanticFlagGroups = self._cb.getAllSemanticFlagGroups.__class__( + self._get_all_semantic_flag_groups + ) self._cb.getFlagRole = self._cb.getFlagRole.__class__(self._get_flag_role) self._cb.getFlagsRequiredForFlagCondition = self._cb.getFlagsRequiredForFlagCondition.__class__( - self._get_flags_required_for_flag_condition) + self._get_flags_required_for_flag_condition + ) self._cb.getFlagsRequiredForSemanticFlagGroup = self._cb.getFlagsRequiredForSemanticFlagGroup.__class__( - self._get_flags_required_for_semantic_flag_group) + self._get_flags_required_for_semantic_flag_group + ) self._cb.getFlagConditionsForSemanticFlagGroup = self._cb.getFlagConditionsForSemanticFlagGroup.__class__( - self._get_flag_conditions_for_semantic_flag_group) + self._get_flag_conditions_for_semantic_flag_group + ) self._cb.freeFlagConditionsForSemanticFlagGroup = self._cb.freeFlagConditionsForSemanticFlagGroup.__class__( - self._free_flag_conditions_for_semantic_flag_group) + self._free_flag_conditions_for_semantic_flag_group + ) self._cb.getFlagsWrittenByFlagWriteType = self._cb.getFlagsWrittenByFlagWriteType.__class__( - self._get_flags_written_by_flag_write_type) + self._get_flags_written_by_flag_write_type + ) self._cb.getSemanticClassForFlagWriteType = self._cb.getSemanticClassForFlagWriteType.__class__( - self._get_semantic_class_for_flag_write_type) - self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__( - self._get_flag_write_low_level_il) + self._get_semantic_class_for_flag_write_type + ) + self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__(self._get_flag_write_low_level_il) self._cb.getFlagConditionLowLevelIL = self._cb.getFlagConditionLowLevelIL.__class__( - self._get_flag_condition_low_level_il) + self._get_flag_condition_low_level_il + ) self._cb.getSemanticFlagGroupLowLevelIL = self._cb.getSemanticFlagGroupLowLevelIL.__class__( - self._get_semantic_flag_group_low_level_il) + self._get_semantic_flag_group_low_level_il + ) self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info) - self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( - self._get_stack_pointer_register) + self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__(self._get_stack_pointer_register) self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) self._cb.getSystemRegisters = self._cb.getSystemRegisters.__class__(self._get_system_registers) @@ -290,15 +307,20 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._cb.freeTypeList = self._cb.freeTypeList.__class__(self._free_type_list) self._cb.assemble = self._cb.assemble.__class__(self._assemble) self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( - self._is_never_branch_patch_available) + self._is_never_branch_patch_available + ) self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__( - self._is_always_branch_patch_available) + self._is_always_branch_patch_available + ) self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__( - self._is_invert_branch_patch_available) + self._is_invert_branch_patch_available + ) self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__( - self._is_skip_and_return_zero_patch_available) + self._is_skip_and_return_zero_patch_available + ) self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__( - self._is_skip_and_return_value_patch_available) + self._is_skip_and_return_value_patch_available + ) self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop) self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch) self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) @@ -313,16 +335,16 @@ class Architecture(metaclass=_ArchitectureMetaClass): self.__dict__['stack_pointer'] = self.__class__.stack_pointer self.__dict__['link_reg'] = self.__class__.link_reg - self._all_regs:Dict[RegisterName, RegisterIndex] = {} - self._full_width_regs:Dict[RegisterName, RegisterIndex] = {} - self._regs_by_index:Dict[RegisterIndex, RegisterName] = {} + self._all_regs: Dict[RegisterName, RegisterIndex] = {} + self._full_width_regs: Dict[RegisterName, RegisterIndex] = {} + self._regs_by_index: Dict[RegisterIndex, RegisterName] = {} self.regs = self.__class__.regs assert self.regs is not None, "Custom Architecture doesn't specify a register map" reg_index = RegisterIndex(0) # Registers used for storage in register stacks must be sequential, so allocate these in order first - self._all_reg_stacks:Dict[RegisterStackName, RegisterStackIndex] = {} - self._reg_stacks_by_index:Dict[RegisterStackIndex, RegisterStackName] = {} + self._all_reg_stacks: Dict[RegisterStackName, RegisterStackIndex] = {} + self._reg_stacks_by_index: Dict[RegisterStackIndex, RegisterStackName] = {} self.reg_stacks = self.__class__.reg_stacks assert self.regs is not None, "Custom Architecture doesn't specify a reg_stacks map" reg_stack_index = RegisterStackIndex(0) @@ -343,7 +365,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._all_reg_stacks[reg_stack] = reg_stack_index self._reg_stacks_by_index[reg_stack_index] = reg_stack rs = self.reg_stacks[reg_stack] - self.reg_stacks[reg_stack] = RegisterStackInfo(rs.storage_regs, rs.top_relative_regs, rs.stack_top_reg, reg_stack_index) + self.reg_stacks[reg_stack] = RegisterStackInfo( + rs.storage_regs, rs.top_relative_regs, rs.stack_top_reg, reg_stack_index + ) reg_stack_index = RegisterStackIndex(reg_stack_index + 1) for reg, info in self.regs.items(): @@ -362,9 +386,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): if info.full_width_reg not in self._full_width_regs: self._full_width_regs[info.full_width_reg] = self._all_regs[info.full_width_reg] - self._flags:Dict[FlagName, FlagIndex] = {} - self._flags_by_index:Dict[FlagIndex, FlagName] = {} - self.flags:List[FlagName] = self.__class__.flags + self._flags: Dict[FlagName, FlagIndex] = {} + self._flags_by_index: Dict[FlagIndex, FlagName] = {} + self.flags: List[FlagName] = self.__class__.flags flag_index = FlagIndex(0) for flag in self.__class__.flags: if flag not in self._flags: @@ -372,9 +396,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._flags_by_index[flag_index] = flag flag_index = FlagIndex(flag_index + 1) - self._flag_write_types:Dict[FlagWriteTypeName, FlagWriteTypeIndex] = {} - self._flag_write_types_by_index:Dict[FlagWriteTypeIndex, FlagWriteTypeName] = {} - self.flag_write_types:List[FlagWriteTypeName] = self.__class__.flag_write_types + self._flag_write_types: Dict[FlagWriteTypeName, FlagWriteTypeIndex] = {} + self._flag_write_types_by_index: Dict[FlagWriteTypeIndex, FlagWriteTypeName] = {} + self.flag_write_types: List[FlagWriteTypeName] = self.__class__.flag_write_types write_type_index = FlagWriteTypeIndex(1) for write_type in self.__class__.flag_write_types: if write_type not in self._flag_write_types: @@ -382,9 +406,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._flag_write_types_by_index[write_type_index] = write_type write_type_index = FlagWriteTypeIndex(write_type_index + 1) - self._semantic_flag_classes:Dict[SemanticClassName, SemanticClassIndex] = {} - self._semantic_flag_classes_by_index:Dict[SemanticClassIndex, SemanticClassName] = {} - self.semantic_flag_classes:List[SemanticClassName] = self.__class__.semantic_flag_classes + self._semantic_flag_classes: Dict[SemanticClassName, SemanticClassIndex] = {} + self._semantic_flag_classes_by_index: Dict[SemanticClassIndex, SemanticClassName] = {} + self.semantic_flag_classes: List[SemanticClassName] = self.__class__.semantic_flag_classes semantic_class_index = SemanticClassIndex(1) for sem_class in self.__class__.semantic_flag_classes: if sem_class not in self._semantic_flag_classes: @@ -392,9 +416,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._semantic_flag_classes_by_index[semantic_class_index] = sem_class semantic_class_index = SemanticClassIndex(semantic_class_index + 1) - self._semantic_flag_groups:Dict[SemanticGroupName, SemanticGroupIndex] = {} - self._semantic_flag_groups_by_index:Dict[SemanticGroupIndex, SemanticGroupName] = {} - self.semantic_flag_groups:List[SemanticGroupName] = self.__class__.semantic_flag_groups + self._semantic_flag_groups: Dict[SemanticGroupName, SemanticGroupIndex] = {} + self._semantic_flag_groups_by_index: Dict[SemanticGroupIndex, SemanticGroupName] = {} + self.semantic_flag_groups: List[SemanticGroupName] = self.__class__.semantic_flag_groups semantic_group_index = SemanticGroupIndex(0) for sem_group in self.__class__.semantic_flag_groups: if sem_group not in self._semantic_flag_groups: @@ -402,20 +426,22 @@ class Architecture(metaclass=_ArchitectureMetaClass): self._semantic_flag_groups_by_index[semantic_group_index] = sem_group semantic_group_index = SemanticGroupIndex(semantic_group_index + 1) - self._flag_roles:Dict[FlagIndex, FlagRole] = {} - self.flag_roles:Dict[FlagName, FlagRole] = self.__class__.flag_roles + self._flag_roles: Dict[FlagIndex, FlagRole] = {} + self.flag_roles: Dict[FlagName, FlagRole] = self.__class__.flag_roles for flag in self.__class__.flag_roles: role = self.__class__.flag_roles[flag] if isinstance(role, str): role = FlagRole[role] self._flag_roles[self._flags[flag]] = role - self.flags_required_for_flag_condition:Dict['lowlevelil.LowLevelILFlagCondition', List[FlagName]] = self.__class__.flags_required_for_flag_condition + self.flags_required_for_flag_condition: Dict['lowlevelil.LowLevelILFlagCondition', + List[FlagName]] = self.__class__.flags_required_for_flag_condition - self._flags_required_by_semantic_flag_group:Dict[SemanticGroupIndex, List[FlagIndex]] = {} - self.flags_required_for_semantic_flag_group:Dict[SemanticGroupName, List[FlagName]] = self.__class__.flags_required_for_semantic_flag_group + self._flags_required_by_semantic_flag_group: Dict[SemanticGroupIndex, List[FlagIndex]] = {} + self.flags_required_for_semantic_flag_group: Dict[ + SemanticGroupName, List[FlagName]] = self.__class__.flags_required_for_semantic_flag_group for group in self.__class__.flags_required_for_semantic_flag_group: - flags:List[FlagIndex] = [] + flags: List[FlagIndex] = [] for flag in self.__class__.flags_required_for_semantic_flag_group[group]: flags.append(self._flags[flag]) self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flags @@ -428,7 +454,8 @@ class Architecture(metaclass=_ArchitectureMetaClass): if sem_class is None: class_cond[0] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] else: - class_cond[self._semantic_flag_classes[sem_class]] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] + class_cond[self._semantic_flag_classes[sem_class] + ] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_cond self._flags_written_by_flag_write_type = {} @@ -452,8 +479,8 @@ class Architecture(metaclass=_ArchitectureMetaClass): self.global_regs = self.__class__.global_regs self.system_regs = self.__class__.system_regs - self._intrinsics:Dict[IntrinsicName, IntrinsicIndex] = {} - self._intrinsics_by_index:Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} + self._intrinsics: Dict[IntrinsicName, IntrinsicIndex] = {} + self._intrinsics_by_index: Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} intrinsic_index = IntrinsicIndex(0) for intrinsic in self.__class__.intrinsics.keys(): if intrinsic not in self._intrinsics: @@ -509,7 +536,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): count = ctypes.c_ulonglong() regs = core.BNGetFullWidthArchitectureRegisters(self.handle, count) assert regs is not None, "core.BNGetFullWidthArchitectureRegisters returned None" - result:List[RegisterName] = [] + result: List[RegisterName] = [] try: for i in range(0, count.value): result.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) @@ -668,8 +695,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): try: buf = ctypes.create_string_buffer(length[0]) ctypes.memmove(buf, data, length[0]) - result = self.get_instruction_low_level_il(buf.raw, addr, - lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) + result = self.get_instruction_low_level_il( + buf.raw, addr, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il)) + ) if result is None: return False length[0] = result @@ -696,7 +724,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): log_error(traceback.format_exc()) return core.BNAllocString("") - def _get_flag_write_type_name(self, ctxt, write_type:FlagWriteTypeIndex): + def _get_flag_write_type_name(self, ctxt, write_type: FlagWriteTypeIndex): try: if write_type in self._flag_write_types_by_index: return core.BNAllocString(self._flag_write_types_by_index[write_type]) @@ -813,7 +841,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): count[0] = 0 return None - def _get_flag_role(self, ctxt, flag:FlagIndex, sem_class:Optional[SemanticClassName]=None): + def _get_flag_role(self, ctxt, flag: FlagIndex, sem_class: Optional[SemanticClassName] = None): if sem_class in self._semantic_flag_classes: assert sem_class is not None _sem_class = self._semantic_flag_classes[sem_class] @@ -933,8 +961,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) else: operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) - return self.get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list, - lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) + return self.get_flag_write_low_level_il( + op, size, write_type_name, flag_name, operand_list, + lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il)) + ) except (KeyError, OSError): log_error(traceback.format_exc()) return False @@ -945,8 +975,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): sem_class_name = self._semantic_flag_classes_by_index[sem_class] else: sem_class_name = None - return self.get_flag_condition_low_level_il(cond, sem_class_name, - lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) + return self.get_flag_condition_low_level_il( + cond, sem_class_name, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il)) + ) except OSError: log_error(traceback.format_exc()) return 0 @@ -957,8 +988,9 @@ class Architecture(metaclass=_ArchitectureMetaClass): sem_group_name = self._semantic_flag_groups_by_index[sem_group] else: sem_group_name = None - return self.get_semantic_flag_group_low_level_il(sem_group_name, - lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) + return self.get_semantic_flag_group_low_level_il( + sem_group_name, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il)) + ) except OSError: log_error(traceback.format_exc()) return 0 @@ -1309,10 +1341,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): log_error(traceback.format_exc()) return False - def get_associated_arch_by_address(self, addr:int) -> Tuple['Architecture', int]: + def get_associated_arch_by_address(self, addr: int) -> Tuple['Architecture', int]: return self, addr - def get_instruction_info(self, data:bytes, addr:int) -> Optional[InstructionInfo]: + def get_instruction_info(self, data: bytes, addr: int) -> Optional[InstructionInfo]: """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. @@ -1344,7 +1376,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ raise NotImplementedError - def get_instruction_text(self, data:bytes, addr:int) -> Tuple[List['function.InstructionTextToken'], int]: + def get_instruction_text(self, data: bytes, addr: int) -> Tuple[List['function.InstructionTextToken'], int]: """ ``get_instruction_text`` returns a tuple containing a list of decoded InstructionTextToken objects and the bytes used at the given virtual address ``addr`` with data ``data``. @@ -1358,13 +1390,15 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ raise NotImplementedError - def get_instruction_low_level_il_instruction(self, bv:'binaryview.BinaryView', addr:int) -> 'lowlevelil.LowLevelILInstruction': + def get_instruction_low_level_il_instruction( + self, bv: 'binaryview.BinaryView', addr: int + ) -> 'lowlevelil.LowLevelILInstruction': il = lowlevelil.LowLevelILFunction(self) data = bv.read(addr, self.max_instr_length) self.get_instruction_low_level_il(data, addr, il) return il[0] - def get_instruction_low_level_il(self, data:bytes, addr:int, il:'lowlevelil.LowLevelILFunction') -> int: + def get_instruction_low_level_il(self, data: bytes, addr: int, il: 'lowlevelil.LowLevelILFunction') -> int: """ ``get_instruction_low_level_il`` appends lowlevelil.ExpressionIndex objects to ``il`` for the instruction at the given virtual address ``addr`` with data ``data``. @@ -1382,7 +1416,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ raise NotImplementedError - def get_low_level_il_from_bytes(self, data:bytes, addr:int) -> 'lowlevelil.LowLevelILInstruction': + def get_low_level_il_from_bytes(self, data: bytes, addr: int) -> 'lowlevelil.LowLevelILInstruction': """ ``get_low_level_il_from_bytes`` converts the instruction in bytes to ``il`` at the given virtual address @@ -1400,7 +1434,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): self.get_instruction_low_level_il(data, addr, func) return func[0] - def get_reg_name(self, reg:RegisterIndex) -> RegisterName: + def get_reg_name(self, reg: RegisterIndex) -> RegisterName: """ ``get_reg_name`` gets a register name from a register index. @@ -1410,7 +1444,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return RegisterName(core.BNGetArchitectureRegisterName(self.handle, reg)) - def get_reg_stack_name(self, reg_stack:RegisterStackIndex) -> RegisterStackName: + def get_reg_stack_name(self, reg_stack: RegisterStackIndex) -> RegisterStackName: """ ``get_reg_stack_name`` gets a register stack name from a register stack number. @@ -1420,14 +1454,14 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return RegisterStackName(core.BNGetArchitectureRegisterStackName(self.handle, reg_stack)) - def get_reg_stack_for_reg(self, reg:RegisterName) -> Optional[RegisterStackName]: + def get_reg_stack_for_reg(self, reg: RegisterName) -> Optional[RegisterStackName]: _reg = self.get_reg_index(reg) result = core.BNGetArchitectureRegisterStackForRegister(self.handle, _reg) if result == 0xffffffff: return None return self.get_reg_stack_name(RegisterStackIndex(result)) - def get_flag_name(self, flag:FlagIndex) -> FlagName: + def get_flag_name(self, flag: FlagIndex) -> FlagName: """ ``get_flag_name`` gets a flag name from a flag index. @@ -1437,7 +1471,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return FlagName(core.BNGetArchitectureFlagName(self.handle, flag)) - def get_reg_index(self, reg:RegisterType) -> RegisterIndex: + def get_reg_index(self, reg: RegisterType) -> RegisterIndex: if isinstance(reg, str): try: index = self.regs[reg].index @@ -1452,7 +1486,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): return RegisterIndex(reg) raise Exception("Attempting to get register index of non-existant register") - def get_reg_stack_index(self, reg_stack:RegisterStackType) -> RegisterStackIndex: + def get_reg_stack_index(self, reg_stack: RegisterStackType) -> RegisterStackIndex: if isinstance(reg_stack, str): reg_stack_info = self.reg_stacks[reg_stack] if reg_stack_info is not None and reg_stack_info.index is not None: @@ -1463,7 +1497,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): return RegisterStackIndex(reg_stack) raise Exception("reg_stack is not convertable to index") - def get_flag_index(self, flag:FlagType) -> FlagIndex: + def get_flag_index(self, flag: FlagType) -> FlagIndex: if isinstance(flag, str): return self._flags[FlagName(flag)] elif isinstance(flag, lowlevelil.ILFlag): @@ -1472,7 +1506,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): return FlagIndex(flag) raise Exception("flag is not convertable to index") - def get_semantic_flag_class_index(self, sem_class:Optional[SemanticClassType]) -> SemanticClassIndex: + def get_semantic_flag_class_index(self, sem_class: Optional[SemanticClassType]) -> SemanticClassIndex: if sem_class is None: return SemanticClassIndex(0) if isinstance(sem_class, str): @@ -1483,7 +1517,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): return SemanticClassIndex(sem_class) raise Exception("sem_class is not convertable to index") - def get_semantic_flag_class_name(self, class_index:SemanticClassIndex) -> SemanticClassName: + def get_semantic_flag_class_name(self, class_index: SemanticClassIndex) -> SemanticClassName: """ ``get_semantic_flag_class_name`` gets the name of a semantic flag class from the index. @@ -1495,14 +1529,14 @@ class Architecture(metaclass=_ArchitectureMetaClass): raise ValueError("argument 'class_index' must be an integer") return self._semantic_flag_classes_by_index[class_index] - def get_semantic_flag_group_index(self, sem_group:SemanticGroupType) -> SemanticGroupIndex: + def get_semantic_flag_group_index(self, sem_group: SemanticGroupType) -> SemanticGroupIndex: if isinstance(sem_group, str): return self._semantic_flag_groups[SemanticGroupName(sem_group)] elif isinstance(sem_group, lowlevelil.ILSemanticFlagGroup): return sem_group.index return sem_group - def get_semantic_flag_group_name(self, group_index:SemanticGroupIndex) -> SemanticGroupName: + def get_semantic_flag_group_name(self, group_index: SemanticGroupIndex) -> SemanticGroupName: """ ``get_semantic_flag_group_name`` gets the name of a semantic flag group from the index. @@ -1514,7 +1548,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): raise ValueError("argument 'group_index' must be an integer") return self._semantic_flag_groups_by_index[group_index] - def get_intrinsic_name(self, intrinsic:IntrinsicIndex) -> IntrinsicName: + def get_intrinsic_name(self, intrinsic: IntrinsicIndex) -> IntrinsicName: """ ``get_intrinsic_name`` gets an intrinsic name from an intrinsic number. @@ -1524,7 +1558,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return IntrinsicName(core.BNGetArchitectureIntrinsicName(self.handle, intrinsic)) - def get_intrinsic_index(self, intrinsic:IntrinsicType) -> IntrinsicIndex: + def get_intrinsic_index(self, intrinsic: IntrinsicType) -> IntrinsicIndex: """ ``get_intrinsic_index`` gets an intrinsic index given an IntrinsicType. @@ -1540,7 +1574,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): return IntrinsicIndex(intrinsic) raise Exception("intrinsic is not convertable to index") - def get_flag_write_type_name(self, write_type:FlagWriteTypeIndex) -> FlagWriteTypeName: + def get_flag_write_type_name(self, write_type: FlagWriteTypeIndex) -> FlagWriteTypeName: """ ``get_flag_write_type_name`` gets the flag write type name for the given flag. @@ -1550,7 +1584,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return FlagWriteTypeName(core.BNGetArchitectureFlagWriteTypeName(self.handle, write_type)) - def get_flag_by_name(self, flag:FlagName) -> FlagIndex: + def get_flag_by_name(self, flag: FlagName) -> FlagIndex: """ ``get_flag_by_name`` get flag name for flag index. @@ -1560,7 +1594,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return self._flags[flag] - def get_flag_write_type_by_name(self, write_type:FlagWriteTypeName) -> FlagWriteTypeIndex: + def get_flag_write_type_by_name(self, write_type: FlagWriteTypeName) -> FlagWriteTypeIndex: """ ``get_flag_write_type_by_name`` gets the flag write type name for the flag write type. @@ -1570,7 +1604,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return self._flag_write_types[write_type] - def get_semantic_flag_class_by_name(self, sem_class:SemanticClassName) -> SemanticClassIndex: + def get_semantic_flag_class_by_name(self, sem_class: SemanticClassName) -> SemanticClassIndex: """ ``get_semantic_flag_class_by_name`` gets the semantic flag class index by name. @@ -1580,7 +1614,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return self._semantic_flag_classes[sem_class] - def get_semantic_flag_group_by_name(self, sem_group:SemanticGroupName) -> SemanticGroupIndex: + def get_semantic_flag_group_by_name(self, sem_group: SemanticGroupName) -> SemanticGroupIndex: """ ``get_semantic_flag_group_by_name`` gets the semantic flag group index by name. @@ -1590,7 +1624,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return self._semantic_flag_groups[sem_group] - def get_flag_role(self, flag:FlagIndex, sem_class:Optional[SemanticClassIndex]= None) -> FlagRole: + def get_flag_role(self, flag: FlagIndex, sem_class: Optional[SemanticClassIndex] = None) -> FlagRole: """ ``get_flag_role`` gets the role of a given flag. @@ -1603,8 +1637,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): return self._flag_roles[flag] return FlagRole.SpecialFlagRole - def get_flag_write_low_level_il(self, op:LowLevelILOperation, size:int, write_type:Optional[FlagWriteTypeName], flag:FlagType, - operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_flag_write_low_level_il( + self, op: LowLevelILOperation, size: int, write_type: Optional[FlagWriteTypeName], flag: FlagType, + operands: List['lowlevelil.ILRegisterType'], il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILOperation op: :param int size: @@ -1620,8 +1656,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): return il.unimplemented() return self.get_default_flag_write_low_level_il(op, size, self._flag_roles[flag], operands, il) - def get_default_flag_write_low_level_il(self, op:'lowlevelil.LowLevelILOperation', size:int, role:FlagRole, - operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_default_flag_write_low_level_il( + self, op: 'lowlevelil.LowLevelILOperation', size: int, role: FlagRole, + operands: List['lowlevelil.ILRegisterType'], il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILOperation op: :param int size: @@ -1643,11 +1681,16 @@ class Architecture(metaclass=_ArchitectureMetaClass): else: operand_list[i].constant = True operand_list[i].value = operand - return lowlevelil.ExpressionIndex(core.BNGetDefaultArchitectureFlagWriteLowLevelIL(self.handle, op, size, - role, operand_list, len(operand_list), il.handle)) + return lowlevelil.ExpressionIndex( + core.BNGetDefaultArchitectureFlagWriteLowLevelIL( + self.handle, op, size, role, operand_list, len(operand_list), il.handle + ) + ) - def get_flag_condition_low_level_il(self, cond:'lowlevelil.LowLevelILFlagCondition', sem_class:Optional[SemanticClassType], - il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_flag_condition_low_level_il( + self, cond: 'lowlevelil.LowLevelILFlagCondition', sem_class: Optional[SemanticClassType], + il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILFlagCondition cond: Flag condition to be computed :param SemanticClassType sem_class: Semantic class to be used (None for default semantics) @@ -1656,8 +1699,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return self.get_default_flag_condition_low_level_il(cond, sem_class, il) - def get_default_flag_condition_low_level_il(self, cond:'lowlevelil.LowLevelILFlagCondition', - sem_class:Optional[SemanticClassType], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_default_flag_condition_low_level_il( + self, cond: 'lowlevelil.LowLevelILFlagCondition', sem_class: Optional[SemanticClassType], + il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILFlagCondition cond: :param SemanticClassType sem_class: @@ -1666,11 +1711,13 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ _class_index = None _class_index = self.get_semantic_flag_class_index(sem_class) - return lowlevelil.ExpressionIndex(core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, - _class_index, il.handle)) + return lowlevelil.ExpressionIndex( + core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, _class_index, il.handle) + ) - def get_semantic_flag_group_low_level_il(self, sem_group:Optional[SemanticGroupType], - il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_semantic_flag_group_low_level_il( + self, sem_group: Optional[SemanticGroupType], il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param Optional[SemanticGroupType] sem_group: :param LowLevelILFunction il: @@ -1678,13 +1725,14 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return il.unimplemented() - def get_flags_required_for_flag_condition(self, cond:'lowlevelil.LowLevelILFlagCondition', - sem_class:Optional[SemanticClassType]=None): + def get_flags_required_for_flag_condition( + self, cond: 'lowlevelil.LowLevelILFlagCondition', sem_class: Optional[SemanticClassType] = None + ): if cond in self.flags_required_for_flag_condition: return self.flags_required_for_flag_condition[cond] return [] - def get_modified_regs_on_write(self, reg:RegisterName) -> List[RegisterName]: + def get_modified_regs_on_write(self, reg: RegisterName) -> List[RegisterName]: """ ``get_modified_regs_on_write`` returns a list of register names that are modified when ``reg`` is written. @@ -1696,13 +1744,13 @@ class Architecture(metaclass=_ArchitectureMetaClass): count = ctypes.c_ulonglong() regs = core.BNGetModifiedArchitectureRegistersOnWrite(self.handle, reg, count) assert regs is not None, "core.BNGetModifiedArchitectureRegistersOnWrite is not None" - result:List[RegisterName] = [] + result: List[RegisterName] = [] for i in range(0, count.value): result.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) core.BNFreeRegisterList(regs) return result - def assemble(self, code:str, addr:int=0) -> bytes: + def assemble(self, code: str, addr: int = 0) -> bytes: """ ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. @@ -1729,7 +1777,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_never_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_never_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. @@ -1749,7 +1797,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_always_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_always_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **always branch**. @@ -1770,7 +1818,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_invert_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_invert_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. @@ -1790,7 +1838,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_skip_and_return_zero_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_skip_and_return_zero_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns zero*. @@ -1813,7 +1861,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_skip_and_return_value_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_skip_and_return_value_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns a value*. @@ -1834,7 +1882,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def convert_to_nop(self, data:bytes, addr:int=0) -> Optional[bytes]: + def convert_to_nop(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop instructions of the same length as data. @@ -1853,7 +1901,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def always_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: + def always_branch(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which always branches. @@ -1875,7 +1923,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def invert_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: + def invert_branch(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which inverts the branch of provided instruction. @@ -1898,7 +1946,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def skip_and_return_value(self, data:bytes, addr:int, value:int) -> Optional[bytes]: + def skip_and_return_value(self, data: bytes, addr: int, value: int) -> Optional[bytes]: """ ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which doesn't call and instead *return a value*. @@ -1917,7 +1965,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return NotImplemented - def is_view_type_constant_defined(self, type_name:str, const_name:str) -> bool: + def is_view_type_constant_defined(self, type_name: str, const_name: str) -> bool: """ :param str type_name: the BinaryView type name of the constant to query @@ -1935,7 +1983,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return core.BNIsBinaryViewTypeArchitectureConstantDefined(self.handle, type_name, const_name) - def get_view_type_constant(self, type_name:str, const_name:str, default_value:int=0) -> int: + def get_view_type_constant(self, type_name: str, const_name: str, default_value: int = 0) -> int: """ ``get_view_type_constant`` retrieves the view type constant for the given type_name and const_name. @@ -1955,7 +2003,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ return core.BNGetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, default_value) - def set_view_type_constant(self, type_name:str, const_name:str, value:int) -> None: + def set_view_type_constant(self, type_name: str, const_name: str, value: int) -> None: """ ``set_view_type_constant`` creates a new binaryview type constant. @@ -1971,7 +2019,7 @@ class Architecture(metaclass=_ArchitectureMetaClass): """ core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) - def register_calling_convention(self, cc:'callingconvention.CallingConvention') -> None: + def register_calling_convention(self, cc: 'callingconvention.CallingConvention') -> None: """ ``register_calling_convention`` registers a new calling convention for the Architecture. @@ -1982,8 +2030,10 @@ class Architecture(metaclass=_ArchitectureMetaClass): _architecture_cache = {} + + class CoreArchitecture(Architecture): - def __init__(self, handle:core.BNArchitecture): + def __init__(self, handle: core.BNArchitecture): super(CoreArchitecture, self).__init__() self.handle = core.handle_of_type(handle, core.BNArchitecture) @@ -1994,8 +2044,9 @@ class CoreArchitecture(Architecture): self.instr_alignment = core.BNGetArchitectureInstructionAlignment(self.handle) self.max_instr_length = core.BNGetArchitectureMaxInstructionLength(self.handle) self.opcode_display_length = core.BNGetArchitectureOpcodeDisplayLength(self.handle) - self.stack_pointer:str = core.BNGetArchitectureRegisterName(self.handle, - core.BNGetArchitectureStackPointerRegister(self.handle)) + self.stack_pointer: str = core.BNGetArchitectureRegisterName( + self.handle, core.BNGetArchitectureStackPointerRegister(self.handle) + ) link_reg = core.BNGetArchitectureLinkRegister(self.handle) if link_reg == 0xffffffff: @@ -2015,8 +2066,9 @@ class CoreArchitecture(Architecture): assert name is not None, "" info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) full_width_reg = RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)) - self.regs[name] = RegisterInfo(full_width_reg, info.size, info.offset, - ImplicitRegisterExtend(info.extend), regs[i]) + self.regs[name] = RegisterInfo( + full_width_reg, info.size, info.offset, ImplicitRegisterExtend(info.extend), regs[i] + ) self._all_regs[name] = regs[i] self._regs_by_index[regs[i]] = name for i in range(0, count.value): @@ -2042,7 +2094,7 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() write_types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) assert write_types is not None, "core.BNGetAllArchitectureFlagWriteTypes returned None" - self._flag_write_types:Dict[str, FlagWriteTypeIndex] = {} + self._flag_write_types: Dict[str, FlagWriteTypeIndex] = {} self._flag_write_types_by_index = {} self.flag_write_types = [] for i in range(0, count.value): @@ -2054,7 +2106,7 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() sem_classes = core.BNGetAllArchitectureSemanticFlagClasses(self.handle, count) - assert sem_classes is not None,"core.BNGetAllArchitectureSemanticFlagClasses returned None" + assert sem_classes is not None, "core.BNGetAllArchitectureSemanticFlagClasses returned None" self._semantic_flag_classes = {} self._semantic_flag_classes_by_index = {} self.semantic_flag_classes = [] @@ -2067,7 +2119,7 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() sem_groups = core.BNGetAllArchitectureSemanticFlagGroups(self.handle, count) - assert sem_groups is not None,"core.BNGetAllArchitectureSemanticFlagGroups returned Non" + assert sem_groups is not None, "core.BNGetAllArchitectureSemanticFlagGroups returned Non" self._semantic_flag_groups = {} self._semantic_flag_groups_by_index = {} self.semantic_flag_groups = [] @@ -2085,7 +2137,7 @@ class CoreArchitecture(Architecture): self.flag_roles[flag] = role self._flag_roles[self._flags[flag]] = role - self.flags_required_for_flag_condition:Dict[LowLevelILFlagCondition, List[FlagName]] = {} + self.flags_required_for_flag_condition: Dict[LowLevelILFlagCondition, List[FlagName]] = {} for cond in LowLevelILFlagCondition: count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count) @@ -2100,8 +2152,9 @@ class CoreArchitecture(Architecture): self.flags_required_for_semantic_flag_group = {} for group in self.semantic_flag_groups: count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup(self.handle, - self._semantic_flag_groups[group], count) + flags = core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup( + self.handle, self._semantic_flag_groups[group], count + ) assert flags is not None, "core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup returned None" flag_indexes = [] flag_names = [] @@ -2116,8 +2169,9 @@ class CoreArchitecture(Architecture): self.flag_conditions_for_semantic_flag_group = {} for group in self.semantic_flag_groups: count = ctypes.c_ulonglong() - conditions = core.BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.handle, - self._semantic_flag_groups[group], count) + conditions = core.BNGetArchitectureFlagConditionsForSemanticFlagGroup( + self.handle, self._semantic_flag_groups[group], count + ) assert conditions is not None, "core.BNGetArchitectureFlagConditionsForSemanticFlagGroup returned None" class_index_cond = {} class_cond = {} @@ -2126,7 +2180,8 @@ class CoreArchitecture(Architecture): if conditions[i].semanticClass == 0: class_cond[None] = conditions[i].condition elif conditions[i].semanticClass in self._semantic_flag_classes_by_index: - class_cond[self._semantic_flag_classes_by_index[conditions[i].semanticClass]] = conditions[i].condition + class_cond[self._semantic_flag_classes_by_index[conditions[i].semanticClass] + ] = conditions[i].condition core.BNFreeFlagConditionsForSemanticFlagGroup(conditions) self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_index_cond self.flag_conditions_for_semantic_flag_group[group] = class_cond @@ -2135,8 +2190,9 @@ class CoreArchitecture(Architecture): self.flags_written_by_flag_write_type = {} for write_type in self.flag_write_types: count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsWrittenByFlagWriteType(self.handle, - self._flag_write_types[write_type], count) + flags = core.BNGetArchitectureFlagsWrittenByFlagWriteType( + self.handle, self._flag_write_types[write_type], count + ) assert flags is not None, "core.BNGetArchitectureFlagsWrittenByFlagWriteType returned None" flag_indexes = [] flag_names = [] @@ -2150,8 +2206,9 @@ class CoreArchitecture(Architecture): self._semantic_class_for_flag_write_type = {} self.semantic_class_for_flag_write_type = {} for write_type in self.flag_write_types: - sem_class = core.BNGetArchitectureSemanticClassForFlagWriteType(self.handle, - self._flag_write_types[write_type]) + sem_class = core.BNGetArchitectureSemanticClassForFlagWriteType( + self.handle, self._flag_write_types[write_type] + ) if sem_class == 0: sem_class_name = None else: @@ -2162,14 +2219,14 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) assert regs is not None, "core.BNGetArchitectureGlobalRegisters returned None" - self.global_regs:List[RegisterName] = [] + self.global_regs: List[RegisterName] = [] for i in range(0, count.value): self.global_regs.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() regs = core.BNGetArchitectureSystemRegisters(self.handle, count) - self.system_regs:List[RegisterName] = [] + self.system_regs: List[RegisterName] = [] for i in range(0, count.value): assert regs is not None, "core.BNGetArchitectureSystemRegisters returned None" self.system_regs.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) @@ -2184,10 +2241,10 @@ class CoreArchitecture(Architecture): for i in range(0, count.value): name = RegisterStackName(core.BNGetArchitectureRegisterStackName(self.handle, regs[i])) info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) - storage:List[RegisterName] = [] + storage: List[RegisterName] = [] for j in range(0, info.storageCount): storage.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j))) - top_rel:List[RegisterName] = [] + top_rel: List[RegisterName] = [] for j in range(0, info.topRelativeCount): reg_name = RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) top_rel.append(reg_name) @@ -2200,9 +2257,9 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) assert intrinsics is not None, "core.BNGetAllArchitectureIntrinsics returned None" - self._intrinsics:Dict[IntrinsicName, IntrinsicIndex] = {} - self._intrinsics_by_index:Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} - self._intrinsics_info:Dict[IntrinsicName, IntrinsicInfo] = {} + self._intrinsics: Dict[IntrinsicName, IntrinsicIndex] = {} + self._intrinsics_by_index: Dict[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} + self._intrinsics_info: Dict[IntrinsicName, IntrinsicInfo] = {} for i in range(count.value): name = IntrinsicName(core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i])) input_count = ctypes.c_ulonglong() @@ -2211,7 +2268,9 @@ class CoreArchitecture(Architecture): input_list = [] for j in range(0, input_count.value): input_name = inputs[j].name - type_obj = types.Type.create(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence) + type_obj = types.Type.create( + core.BNNewTypeReference(inputs[j].type), confidence=inputs[j].typeConfidence + ) input_list.append(IntrinsicInput(type_obj, input_name)) core.BNFreeNameAndTypeList(inputs, input_count.value) output_count = ctypes.c_ulonglong() @@ -2219,7 +2278,9 @@ class CoreArchitecture(Architecture): assert outputs is not None, "core.BNGetArchitectureIntrinsicOutputs returned None" output_list = [] for j in range(output_count.value): - output_list.append(types.Type.create(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence)) + output_list.append( + types.Type.create(core.BNNewTypeReference(outputs[j].type), confidence=outputs[j].confidence) + ) core.BNFreeOutputTypeList(outputs, output_count.value) self._intrinsics_info[name] = IntrinsicInfo(input_list, output_list) self._intrinsics[name] = intrinsics[i] @@ -2234,13 +2295,13 @@ class CoreArchitecture(Architecture): global _architecture_cache return _architecture_cache.get(ctypes.addressof(handle.contents)) or cls(handle) - def get_associated_arch_by_address(self, addr:int) -> Tuple['Architecture', int]: + def get_associated_arch_by_address(self, addr: int) -> Tuple['Architecture', int]: new_addr = ctypes.c_ulonglong() new_addr.value = addr result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) - return CoreArchitecture._from_cache(handle = result), new_addr.value + return CoreArchitecture._from_cache(handle=result), new_addr.value - def get_instruction_info(self, data:bytes, addr:int) -> Optional[InstructionInfo]: + def get_instruction_info(self, data: bytes, addr: int) -> Optional[InstructionInfo]: """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2271,7 +2332,7 @@ class CoreArchitecture(Architecture): result.add_branch(BranchType(info.branchType[i]), target, arch) return result - def get_instruction_text(self, data:bytes, addr:int) -> Tuple[List['function.InstructionTextToken'], int]: + def get_instruction_text(self, data: bytes, addr: int) -> Tuple[List['function.InstructionTextToken'], int]: """ ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2295,7 +2356,7 @@ class CoreArchitecture(Architecture): core.BNFreeInstructionText(tokens, count.value) return result, result_length - def get_instruction_low_level_il(self, data:bytes, addr:int, il:lowlevelil.LowLevelILFunction) -> Optional[int]: + def get_instruction_low_level_il(self, data: bytes, addr: int, il: lowlevelil.LowLevelILFunction) -> Optional[int]: """ ``get_instruction_low_level_il`` appends lowlevelil.ExpressionIndex objects to ``il`` for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2317,8 +2378,10 @@ class CoreArchitecture(Architecture): return length.value return None - def get_flag_write_low_level_il(self, op:LowLevelILOperation, size:int, write_type:FlagWriteTypeName, - flag:FlagType, operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_flag_write_low_level_il( + self, op: LowLevelILOperation, size: int, write_type: FlagWriteTypeName, flag: FlagType, + operands: List['lowlevelil.ILRegisterType'], il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILOperation op: :param int size: @@ -2341,11 +2404,16 @@ class CoreArchitecture(Architecture): else: operand_list[i].constant = True operand_list[i].value = operand - return lowlevelil.ExpressionIndex(core.BNGetArchitectureFlagWriteLowLevelIL(self.handle, op, size, - self._flag_write_types[write_type], flag, operand_list, len(operand_list), il.handle)) + return lowlevelil.ExpressionIndex( + core.BNGetArchitectureFlagWriteLowLevelIL( + self.handle, op, size, self._flag_write_types[write_type], flag, operand_list, len(operand_list), + il.handle + ) + ) - def get_flag_condition_low_level_il(self, cond:LowLevelILFlagCondition, sem_class:SemanticClassType, - il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_flag_condition_low_level_il( + self, cond: LowLevelILFlagCondition, sem_class: SemanticClassType, il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param LowLevelILFlagCondition cond: Flag condition to be computed :param str sem_class: Semantic class to be used (None for default semantics) @@ -2353,20 +2421,24 @@ class CoreArchitecture(Architecture): :rtype: ExpressionIndex """ class_index = self.get_semantic_flag_class_index(sem_class) - return lowlevelil.ExpressionIndex(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, - class_index, il.handle)) + return lowlevelil.ExpressionIndex( + core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, class_index, il.handle) + ) - def get_semantic_flag_group_low_level_il(self, sem_group:SemanticGroupName, - il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.ExpressionIndex': + def get_semantic_flag_group_low_level_il( + self, sem_group: SemanticGroupName, il: 'lowlevelil.LowLevelILFunction' + ) -> 'lowlevelil.ExpressionIndex': """ :param str sem_group: :param LowLevelILFunction il: :rtype: ExpressionIndex """ group_index = self.get_semantic_flag_group_index(sem_group) - return lowlevelil.ExpressionIndex(core.BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group_index, il.handle)) + return lowlevelil.ExpressionIndex( + core.BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group_index, il.handle) + ) - def assemble(self, code:str, addr:int=0) -> bytes: + def assemble(self, code: str, addr: int = 0) -> bytes: """ ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. @@ -2389,7 +2461,7 @@ class CoreArchitecture(Architecture): raise ValueError(f"Could not assemble: {error_str}") return bytes(result) - def is_never_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_never_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. @@ -2409,7 +2481,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_always_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_always_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **always branch**. @@ -2430,7 +2502,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_invert_branch_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_invert_branch_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. @@ -2450,7 +2522,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_skip_and_return_zero_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_skip_and_return_zero_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns zero*. @@ -2473,7 +2545,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data)) - def is_skip_and_return_value_patch_available(self, data:bytes, addr:int=0) -> bool: + def is_skip_and_return_value_patch_available(self, data: bytes, addr: int = 0) -> bool: """ ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns a value*. @@ -2494,7 +2566,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data)) - def convert_to_nop(self, data:bytes, addr:int=0) -> Optional[bytes]: + def convert_to_nop(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop instructions of the same length as data. @@ -2517,7 +2589,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def always_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: + def always_branch(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which always branches. @@ -2543,7 +2615,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def invert_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: + def invert_branch(self, data: bytes, addr: int = 0) -> Optional[bytes]: """ ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which inverts the branch of provided instruction. @@ -2570,7 +2642,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def skip_and_return_value(self, data:bytes, addr:int, value:int) -> Optional[bytes]: + def skip_and_return_value(self, data: bytes, addr: int, value: int) -> Optional[bytes]: """ ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which doesn't call and instead *return a value*. @@ -2594,7 +2666,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def get_flag_role(self, flag:FlagIndex, sem_class:Optional[SemanticClassIndex]= None) -> FlagRole: + def get_flag_role(self, flag: FlagIndex, sem_class: Optional[SemanticClassIndex] = None) -> FlagRole: """ ``get_flag_role`` gets the role of a given flag. @@ -2607,8 +2679,9 @@ class CoreArchitecture(Architecture): _sem_class = self.get_semantic_flag_class_index(sem_class) return FlagRole(core.BNGetArchitectureFlagRole(self.handle, flag, _sem_class)) - def get_flags_required_for_flag_condition(self, cond:LowLevelILFlagCondition, - sem_class:Optional[SemanticClassType]=None) -> List[FlagName]: + def get_flags_required_for_flag_condition( + self, cond: LowLevelILFlagCondition, sem_class: Optional[SemanticClassType] = None + ) -> List[FlagName]: _sem_class = self.get_semantic_flag_class_index(sem_class) count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, _sem_class, count) @@ -2621,7 +2694,7 @@ class CoreArchitecture(Architecture): class ArchitectureHook(CoreArchitecture): - def __init__(self, base_arch:'Architecture'): + def __init__(self, base_arch: 'Architecture'): self._base_arch = base_arch super(ArchitectureHook, self).__init__(base_arch.handle) @@ -2659,9 +2732,10 @@ class ArchitectureHook(CoreArchitecture): return self._base_arch @base_arch.setter - def base_arch(self, value:'Architecture') -> None: + def base_arch(self, value: 'Architecture') -> None: self._base_arch = value + @dataclass class InstructionTextToken: """ @@ -2711,24 +2785,25 @@ class InstructionTextToken: ========================== ============================================ """ - type:Union[InstructionTextTokenType, int] - text:str - value:int = 0 - size:int = 0 - operand:int = 0xffffffff - context:InstructionTextTokenContext = InstructionTextTokenContext.NoTokenContext - address:int = 0 - confidence:int = core.max_confidence - typeNames:List[str] = field(default_factory=list) - width:int = 0 + type: Union[InstructionTextTokenType, int] + text: str + value: int = 0 + size: int = 0 + operand: int = 0xffffffff + context: InstructionTextTokenContext = InstructionTextTokenContext.NoTokenContext + address: int = 0 + confidence: int = core.max_confidence + typeNames: List[str] = field(default_factory=list) + width: int = 0 def __post_init__(self): if self.width == 0: self.width = len(self.text) @staticmethod - def _from_core_struct(tokens:'ctypes.pointer[core.BNInstructionTextToken]', count:int) -> List['InstructionTextToken']: - result:List['InstructionTextToken'] = [] + def _from_core_struct(tokens: 'ctypes.pointer[core.BNInstructionTextToken]', + count: int) -> List['InstructionTextToken']: + result: List['InstructionTextToken'] = [] for j in range(count): token_type = InstructionTextTokenType(tokens[j].type) text = tokens[j].text @@ -2747,11 +2822,15 @@ class InstructionTextToken: typeNames.append(tokens[j].typeNames[i].decode("utf-8")) else: typeNames.append(tokens[j].typeNames[i]) - result.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence, typeNames, width)) + result.append( + InstructionTextToken( + token_type, text, value, size, operand, context, address, confidence, typeNames, width + ) + ) return result @staticmethod - def _get_core_struct(tokens:List['InstructionTextToken']) -> 'ctypes.Array[core.BNInstructionTextToken]': + def _get_core_struct(tokens: List['InstructionTextToken']) -> 'ctypes.Array[core.BNInstructionTextToken]': """ Helper method for converting between core.BNInstructionTextToken and InstructionTextToken lists """ result = (core.BNInstructionTextToken * len(tokens))() for j in range(len(tokens)): diff --git a/python/associateddatastore.py b/python/associateddatastore.py index 256437a0..66434d56 100644 --- a/python/associateddatastore.py +++ b/python/associateddatastore.py @@ -21,14 +21,15 @@ import copy from typing import Any + class _AssociatedDataStore(dict): _defaults = {} @classmethod - def set_default(cls, name:str, value:Any): + def set_default(cls, name: str, value: Any): cls._defaults[name] = value - def __getattr__(self, name:str) -> Any: + def __getattr__(self, name: str) -> Any: if name in self.__dict__: return self.__dict__[name] if name not in self: @@ -38,8 +39,8 @@ class _AssociatedDataStore(dict): return result return self.__getitem__(name) - def __setattr__(self, name:str, value:Any): + def __setattr__(self, name: str, value: Any): self.__setitem__(name, value) - def __delattr__(self, name:str): + def __delattr__(self, name: str): self.__delitem__(name) diff --git a/python/basicblock.py b/python/basicblock.py index d504933b..24f549d7 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -30,13 +30,14 @@ from . import architecture from . import highlight as _highlight from . import function as _function + @dataclass(frozen=True) class BasicBlockEdge: - type:BranchType - source:'BasicBlock' - target:'BasicBlock' - back_edge:bool - fall_through:bool + type: BranchType + source: 'BasicBlock' + target: 'BasicBlock' + back_edge: bool + fall_through: bool def __repr__(self): if self.type == BranchType.UnresolvedBranch: @@ -48,14 +49,14 @@ class BasicBlockEdge: class BasicBlock: - def __init__(self, handle:core.BNBasicBlockHandle, view:Optional['binaryview.BinaryView']=None): + def __init__(self, handle: core.BNBasicBlockHandle, view: Optional['binaryview.BinaryView'] = None): self._view = view _handle = core.BNBasicBlockHandle - self.handle:core.BNBasicBlockHandle = ctypes.cast(handle, _handle) + self.handle: core.BNBasicBlockHandle = ctypes.cast(handle, _handle) self._arch = None self._func = None - self._instStarts:Optional[List[int]] = None - self._instLengths:Optional[List[int]] = None + self._instStarts: Optional[List[int]] = None + self._instLengths: Optional[List[int]] = None def __del__(self): if core is not None: @@ -129,7 +130,7 @@ class BasicBlock: data = self.view.read(start, length) return self.arch.get_instruction_text(data, start) - def __contains__(self, i:int): + def __contains__(self, i: int): return self.start <= i < self.end def _buildStartCache(self) -> None: @@ -142,13 +143,13 @@ class BasicBlock: start = self.start while start < self.end: length = self.view.get_instruction_length(start, self.arch) - if length == 0: # invalid instruction. avoid infinite loop + if length == 0: # invalid instruction. avoid infinite loop break self._instLengths.append(length) self._instStarts.append(start) start += length - def _create_instance(self, handle:core.BNBasicBlockHandle, view:'binaryview.BinaryView') -> 'BasicBlock': + def _create_instance(self, handle: core.BNBasicBlockHandle, view: 'binaryview.BinaryView') -> 'BasicBlock': """Internal method used to instantiate child instances""" return BasicBlock(handle, view) @@ -220,12 +221,11 @@ class BasicBlock: """Basic block index in list of blocks for the function (read-only)""" return core.BNGetBasicBlockIndex(self.handle) - - def _make_edges(self, edges, count:int, direction:bool) -> List[BasicBlockEdge]: + def _make_edges(self, edges, count: int, direction: bool) -> List[BasicBlockEdge]: assert edges is not None, "Got empty edges list from core" if self.view is None: raise ValueError("Attempting to get BasicBlock edges when BinaryView is None") - result:List[BasicBlockEdge] = [] + result: List[BasicBlockEdge] = [] try: for i in range(0, count): branch_type = BranchType(edges[i].type) @@ -241,7 +241,6 @@ class BasicBlock: finally: core.BNFreeBasicBlockEdgeList(edges, count) - @property def outgoing_edges(self) -> List[BasicBlockEdge]: """List of basic block outgoing edges (read-only)""" @@ -254,7 +253,6 @@ class BasicBlock: count = ctypes.c_ulonglong(0) return self._make_edges(core.BNGetBasicBlockIncomingEdges(self.handle, count), count.value, True) - @property def has_undetermined_outgoing_edges(self) -> bool: """Whether basic block has undetermined outgoing edges (read-only)""" @@ -266,7 +264,7 @@ class BasicBlock: return core.BNBasicBlockCanExit(self.handle) @can_exit.setter - def can_exit(self, value:bool) -> None: + def can_exit(self, value: bool) -> None: """Sets whether basic block can return or is tagged as 'No Return'""" core.BNBasicBlockSetCanExit(self.handle, value) @@ -275,9 +273,9 @@ class BasicBlock: """Whether basic block has any invalid instructions (read-only)""" return core.BNBasicBlockHasInvalidInstructions(self.handle) - def _make_blocks(self, blocks, count:int) -> List['BasicBlock']: + def _make_blocks(self, blocks, count: int) -> List['BasicBlock']: assert blocks is not None, "core returned empty block list" - result:List['BasicBlock'] = [] + result: List['BasicBlock'] = [] try: for i in range(0, count): handle = core.BNNewBasicBlockReference(blocks[i]) @@ -295,12 +293,11 @@ class BasicBlock: count = ctypes.c_ulonglong() return self._make_blocks(core.BNGetBasicBlockDominators(self.handle, count, False), count.value) - @property def post_dominators(self) -> List['BasicBlock']: """List of dominators for this basic block (read-only)""" if self.view is None: - raise Exception("Attempting to call BasicBlock.post_dominators when BinaryView is None") + raise Exception("Attempting to call BasicBlock.post_dominators when BinaryView is None") count = ctypes.c_ulonglong() return self._make_blocks(core.BNGetBasicBlockDominators(self.handle, count, True), count.value) @@ -403,7 +400,7 @@ class BasicBlock: return _highlight.HighlightColor._from_core_struct(core.BNGetBasicBlockHighlight(self.handle)) @highlight.setter - def highlight(self, value:'_highlight.HighlightColor') -> None: + def highlight(self, value: '_highlight.HighlightColor') -> None: self.set_user_highlight(value) @property @@ -427,10 +424,10 @@ class BasicBlock: return core.BNIsHighLevelILBasicBlock(self.handle) @staticmethod - def get_iterated_dominance_frontier(blocks:List['BasicBlock']) -> List['BasicBlock']: + def get_iterated_dominance_frontier(blocks: List['BasicBlock']) -> List['BasicBlock']: if len(blocks) == 0: return [] - block_set = (ctypes.POINTER(core.BNBasicBlock) * len(blocks))() # type: ignore + block_set = (ctypes.POINTER(core.BNBasicBlock) * len(blocks))() # type: ignore for i in range(len(blocks)): block_set[i] = blocks[i].handle count = ctypes.c_ulonglong() @@ -449,7 +446,8 @@ class BasicBlock: def mark_recent_use(self) -> None: core.BNMarkBasicBlockAsRecentlyUsed(self.handle) - def get_disassembly_text(self, settings:'_function.DisassemblySettings'=None) -> List['_function.DisassemblyTextLine']: + def get_disassembly_text(self, + settings: '_function.DisassemblySettings' = None) -> List['_function.DisassemblyTextLine']: """ ``get_disassembly_text`` returns a list of DisassemblyTextLine objects for the current basic block. @@ -471,7 +469,7 @@ class BasicBlock: for i in range(0, count.value): addr = lines[i].addr if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(self, 'il_function'): - il_instr = self.il_function[lines[i].instrIndex] # type: ignore + il_instr = self.il_function[lines[i].instrIndex] # type: ignore else: il_instr = None color = _highlight.HighlightColor._from_core_struct(lines[i].highlight) @@ -481,7 +479,7 @@ class BasicBlock: finally: core.BNFreeDisassemblyTextLines(lines, count.value) - def set_auto_highlight(self, color:'_highlight.HighlightColor') -> None: + def set_auto_highlight(self, color: '_highlight.HighlightColor') -> None: """ ``set_auto_highlight`` highlights the current BasicBlock with the supplied color. @@ -495,7 +493,7 @@ class BasicBlock: color = _highlight.HighlightColor(color) core.BNSetAutoBasicBlockHighlight(self.handle, color._to_core_struct()) - def set_user_highlight(self, color:'_highlight.HighlightColor') -> None: + def set_user_highlight(self, color: '_highlight.HighlightColor') -> None: """ ``set_user_highlight`` highlights the current BasicBlock with the supplied color @@ -511,7 +509,7 @@ class BasicBlock: color = _highlight.HighlightColor(color) core.BNSetUserBasicBlockHighlight(self.handle, color._to_core_struct()) - def get_instruction_containing_address(self, addr:int) -> Tuple[bool, int]: + def get_instruction_containing_address(self, addr: int) -> Tuple[bool, int]: start = ctypes.c_uint64() - ret:bool = core.BNGetBasicBlockInstructionContainingAddress(self.handle, addr, start) + ret: bool = core.BNGetBasicBlockInstructionContainingAddress(self.handle, addr, start) return ret, start.value diff --git a/python/binaryview.py b/python/binaryview.py index acc437c7..ce9cca92 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -34,15 +34,14 @@ from dataclasses import dataclass import collections from collections import defaultdict, OrderedDict, deque - # Binary Ninja components import binaryninja from . import _binaryninjacore as core -from .enums import (AnalysisState, SymbolType, - Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag, - TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, - RegisterValueType) -from . import associateddatastore # required for _BinaryViewAssociatedDataStore +from .enums import ( + AnalysisState, SymbolType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag, + TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, RegisterValueType +) +from . import associateddatastore # required for _BinaryViewAssociatedDataStore from .log import log_error, log_warn from . import typelibrary from . import fileaccessor @@ -67,7 +66,6 @@ from . import function as _function from . import types as _types from . import platform as _platform - PathType = Union[str, os.PathLike] InstructionsType = Generator[Tuple[List['_function.InstructionTextToken'], int], None, None] NotificationType = Mapping['BinaryDataNotification', 'BinaryDataNotificationCallbacks'] @@ -76,14 +74,16 @@ DataMatchCallbackType = Callable[[int, 'databuffer.DataBuffer'], bool] LineMatchCallbackType = Callable[[int, 'lineardisassembly.LinearDisassemblyLine'], bool] StringOrType = Union[str, '_types.Type', '_types.TypeBuilder'] + class RelocationWriteException(Exception): pass + @dataclass(frozen=True) class ReferenceSource: - function:Optional['_function.Function'] - arch:Optional['architecture.Architecture'] - address:int + function: Optional['_function.Function'] + arch: Optional['architecture.Architecture'] + address: int def __repr__(self): if self.arch: @@ -92,7 +92,7 @@ class ReferenceSource: return f"" @classmethod - def _from_core_struct(cls, view:'BinaryView', ref:core.BNReferenceSource) -> 'ReferenceSource': + def _from_core_struct(cls, view: 'BinaryView', ref: core.BNReferenceSource) -> 'ReferenceSource': if ref.func: func = _function.Function(view, core.BNNewFunctionReference(ref.func)) else: @@ -109,89 +109,95 @@ class BinaryDataNotification: def __init__(self): pass - def data_written(self, view:'BinaryView', offset:int, length:int) -> None: + def data_written(self, view: 'BinaryView', offset: int, length: int) -> None: pass - def data_inserted(self, view:'BinaryView', offset:int, length:int) -> None: + def data_inserted(self, view: 'BinaryView', offset: int, length: int) -> None: pass - def data_removed(self, view:'BinaryView', offset:int, length:int) -> None: + def data_removed(self, view: 'BinaryView', offset: int, length: int) -> None: pass - def function_added(self, view:'BinaryView', func:'_function.Function') -> None: + def function_added(self, view: 'BinaryView', func: '_function.Function') -> None: pass - def function_removed(self, view:'BinaryView', func:'_function.Function') -> None: + def function_removed(self, view: 'BinaryView', func: '_function.Function') -> None: pass - def function_updated(self, view:'BinaryView', func:'_function.Function') -> None: + def function_updated(self, view: 'BinaryView', func: '_function.Function') -> None: pass - def function_update_requested(self, view:'BinaryView', func:'_function.Function') -> None: + def function_update_requested(self, view: 'BinaryView', func: '_function.Function') -> None: pass - def data_var_added(self, view:'BinaryView', var:'DataVariable') -> None: + def data_var_added(self, view: 'BinaryView', var: 'DataVariable') -> None: pass - def data_var_removed(self, view:'BinaryView', var:'DataVariable') -> None: + def data_var_removed(self, view: 'BinaryView', var: 'DataVariable') -> None: pass - def data_var_updated(self, view:'BinaryView', var:'DataVariable') -> None: + def data_var_updated(self, view: 'BinaryView', var: 'DataVariable') -> None: pass - def data_metadata_updated(self, view:'BinaryView', offset:int) -> None: + def data_metadata_updated(self, view: 'BinaryView', offset: int) -> None: pass - def tag_type_updated(self, view:'BinaryView', tag_type) -> None: + def tag_type_updated(self, view: 'BinaryView', tag_type) -> None: pass - def tag_added(self, view:'BinaryView', tag:'Tag', ref_type:TagReferenceType, auto_defined:bool, - arch:Optional['architecture.Architecture'], func:Optional[_function.Function], addr:int) -> None: + def tag_added( + self, view: 'BinaryView', tag: 'Tag', ref_type: TagReferenceType, auto_defined: bool, + arch: Optional['architecture.Architecture'], func: Optional[_function.Function], addr: int + ) -> None: pass - def tag_updated(self, view:'BinaryView', tag:'Tag', ref_type:TagReferenceType, auto_defined:bool, - arch:Optional['architecture.Architecture'], func:Optional[_function.Function], addr:int) -> None: + def tag_updated( + self, view: 'BinaryView', tag: 'Tag', ref_type: TagReferenceType, auto_defined: bool, + arch: Optional['architecture.Architecture'], func: Optional[_function.Function], addr: int + ) -> None: pass - def tag_removed(self, view:'BinaryView', tag:'Tag', ref_type:TagReferenceType, auto_defined:bool, - arch:Optional['architecture.Architecture'], func:Optional[_function.Function], addr:int) -> None: + def tag_removed( + self, view: 'BinaryView', tag: 'Tag', ref_type: TagReferenceType, auto_defined: bool, + arch: Optional['architecture.Architecture'], func: Optional[_function.Function], addr: int + ) -> None: pass - def symbol_added(self, view:'BinaryView', sym:'_types.CoreSymbol') -> None: + def symbol_added(self, view: 'BinaryView', sym: '_types.CoreSymbol') -> None: pass - def symbol_updated(self, view:'BinaryView', sym:'_types.CoreSymbol') -> None: + def symbol_updated(self, view: 'BinaryView', sym: '_types.CoreSymbol') -> None: pass - def symbol_removed(self, view:'BinaryView', sym:'_types.CoreSymbol') -> None: + def symbol_removed(self, view: 'BinaryView', sym: '_types.CoreSymbol') -> None: pass - def string_found(self, view:'BinaryView', string_type:StringType, offset:int, length:int) -> None: + def string_found(self, view: 'BinaryView', string_type: StringType, offset: int, length: int) -> None: pass - def string_removed(self, view:'BinaryView', string_type:StringType, offset:int, length:int) -> None: + def string_removed(self, view: 'BinaryView', string_type: StringType, offset: int, length: int) -> None: pass - def type_defined(self, view:'BinaryView', name:'_types.QualifiedName', type:'_types.Type') -> None: + def type_defined(self, view: 'BinaryView', name: '_types.QualifiedName', type: '_types.Type') -> None: pass - def type_undefined(self, view:'BinaryView', name:'_types.QualifiedName', type:'_types.Type') -> None: + def type_undefined(self, view: 'BinaryView', name: '_types.QualifiedName', type: '_types.Type') -> None: pass - def type_ref_changed(self, view:'BinaryView', name:'_types.QualifiedName', type:'_types.Type') -> None: + def type_ref_changed(self, view: 'BinaryView', name: '_types.QualifiedName', type: '_types.Type') -> None: pass - def type_field_ref_changed(self, view:'BinaryView', name:'_types.QualifiedName', offset: int) -> None: + def type_field_ref_changed(self, view: 'BinaryView', name: '_types.QualifiedName', offset: int) -> None: pass + class StringReference: _decodings = { - StringType.AsciiString: "ascii", - StringType.Utf8String: "utf-8", - StringType.Utf16String: "utf-16", - StringType.Utf32String: "utf-32", + StringType.AsciiString: "ascii", StringType.Utf8String: "utf-8", StringType.Utf16String: "utf-16", + StringType.Utf32String: "utf-32", } - def __init__(self, bv:'BinaryView', string_type:StringType, start:int, length:int): + + def __init__(self, bv: 'BinaryView', string_type: StringType, start: int, length: int): self._type = string_type self._start = start self._length = length @@ -219,7 +225,7 @@ class StringReference: return self._type @type.setter - def type(self, value:StringType) -> None: + def type(self, value: StringType) -> None: self._type = value @property @@ -227,7 +233,7 @@ class StringReference: return self._start @start.setter - def start(self, value:int) -> None: + def start(self, value: int) -> None: self._start = value @property @@ -254,7 +260,10 @@ class AnalysisCompletionEvent: >>> """ _pending_analysis_completion_events = {} - def __init__(self, view:'BinaryView', callback:Union[Callable[['AnalysisCompletionEvent'], None], Callable[[], None]]): + + def __init__( + self, view: 'BinaryView', callback: Union[Callable[['AnalysisCompletionEvent'], None], Callable[[], None]] + ): self._view = view self.callback = callback self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify) @@ -274,9 +283,9 @@ class AnalysisCompletionEvent: arg_offset = inspect.ismethod(self.callback) callback_spec = inspect.getargspec(self.callback) if len(callback_spec.args) > arg_offset: - self.callback(self) # type: ignore + self.callback(self) # type: ignore else: - self.callback() # type: ignore + self.callback() # type: ignore except: log_error(traceback.format_exc()) @@ -300,7 +309,7 @@ class AnalysisCompletionEvent: return self._view @view.setter - def view(self, value:'BinaryView') -> None: + def view(self, value: 'BinaryView') -> None: self._view = value @@ -331,16 +340,18 @@ class BinaryViewEvent: _binaryview_events = {} @classmethod - def register(cls, event_type:BinaryViewEventType, callback:BinaryViewEventCallback) -> None: - callback_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._notify(view, callback)) + def register(cls, event_type: BinaryViewEventType, callback: BinaryViewEventCallback) -> None: + callback_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, + ctypes.POINTER(core.BNBinaryView + ))(lambda ctxt, view: cls._notify(view, callback)) core.BNRegisterBinaryViewEvent(event_type, callback_obj, None) cls._binaryview_events[len(cls._binaryview_events)] = callback_obj @staticmethod - def _notify(view:core.BNBinaryView, callback:BinaryViewEventCallback) -> None: + def _notify(view: core.BNBinaryView, callback: BinaryViewEventCallback) -> None: try: - file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) + view_obj = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) callback(view_obj) except: log_error(traceback.format_exc()) @@ -348,10 +359,10 @@ class BinaryViewEvent: @dataclass(frozen=True) class ActiveAnalysisInfo: - func:'_function.Function' - analysis_time:int - update_count:int - submit_count:int + func: '_function.Function' + analysis_time: int + update_count: int + submit_count: int def __repr__(self): return f"" @@ -359,9 +370,9 @@ class ActiveAnalysisInfo: @dataclass(frozen=True) class AnalysisInfo: - state:AnalysisState - analysis_time:int - active_info:List[ActiveAnalysisInfo] + state: AnalysisState + analysis_time: int + active_info: List[ActiveAnalysisInfo] def __repr__(self): return f"" @@ -369,9 +380,9 @@ class AnalysisInfo: @dataclass(frozen=True) class AnalysisProgress: - state:AnalysisState - count:int - total:int + state: AnalysisState + count: int + total: int def __str__(self): if self.state == AnalysisState.InitialState: @@ -391,7 +402,7 @@ class AnalysisProgress: class BinaryDataNotificationCallbacks: - def __init__(self, view:'BinaryView', notify:'BinaryDataNotification'): + def __init__(self, view: 'BinaryView', notify: 'BinaryDataNotification'): self._view = view self._notify = notify self._cb = core.BNBinaryDataNotification() @@ -427,73 +438,75 @@ class BinaryDataNotificationCallbacks: def _unregister(self) -> None: core.BNUnregisterDataNotification(self._view.handle, self._cb) - def _data_written(self, ctxt, view:core.BNBinaryView, offset:int, length:int) -> None: + def _data_written(self, ctxt, view: core.BNBinaryView, offset: int, length: int) -> None: try: self._notify.data_written(self._view, offset, length) except OSError: log_error(traceback.format_exc()) - def _data_inserted(self, ctxt, view:core.BNBinaryView, offset:int, length:int) -> None: + def _data_inserted(self, ctxt, view: core.BNBinaryView, offset: int, length: int) -> None: try: self._notify.data_inserted(self._view, offset, length) except: log_error(traceback.format_exc()) - def _data_removed(self, ctxt, view:core.BNBinaryView, offset:int, length:int) -> None: + def _data_removed(self, ctxt, view: core.BNBinaryView, offset: int, length: int) -> None: try: self._notify.data_removed(self._view, offset, length) except: log_error(traceback.format_exc()) - def _function_added(self, ctxt, view:core.BNBinaryView, func:core.BNFunction) -> None: + def _function_added(self, ctxt, view: core.BNBinaryView, func: core.BNFunction) -> None: try: self._notify.function_added(self._view, _function.Function(self._view, core.BNNewFunctionReference(func))) except: log_error(traceback.format_exc()) - def _function_removed(self, ctxt, view:core.BNBinaryView, func:core.BNFunction) -> None: + def _function_removed(self, ctxt, view: core.BNBinaryView, func: core.BNFunction) -> None: try: self._notify.function_removed(self._view, _function.Function(self._view, core.BNNewFunctionReference(func))) except: log_error(traceback.format_exc()) - def _function_updated(self, ctxt, view:core.BNBinaryView, func:core.BNFunction) -> None: + def _function_updated(self, ctxt, view: core.BNBinaryView, func: core.BNFunction) -> None: try: self._notify.function_updated(self._view, _function.Function(self._view, core.BNNewFunctionReference(func))) except: log_error(traceback.format_exc()) - def _function_update_requested(self, ctxt, view:core.BNBinaryView, func:core.BNFunction) -> None: + def _function_update_requested(self, ctxt, view: core.BNBinaryView, func: core.BNFunction) -> None: try: - self._notify.function_update_requested(self._view, _function.Function(self._view, core.BNNewFunctionReference(func))) + self._notify.function_update_requested( + self._view, _function.Function(self._view, core.BNNewFunctionReference(func)) + ) except: log_error(traceback.format_exc()) - def _data_var_added(self, ctxt, view:core.BNBinaryView, var:core.BNDataVariable) -> None: + def _data_var_added(self, ctxt, view: core.BNBinaryView, var: core.BNDataVariable) -> None: try: self._notify.data_var_added(self._view, DataVariable.from_core_struct(var[0], self._view)) except: log_error(traceback.format_exc()) - def _data_var_removed(self, ctxt, view:core.BNBinaryView, var:core.BNDataVariable) -> None: + def _data_var_removed(self, ctxt, view: core.BNBinaryView, var: core.BNDataVariable) -> None: try: self._notify.data_var_removed(self._view, DataVariable.from_core_struct(var[0], self._view)) except: log_error(traceback.format_exc()) - def _data_var_updated(self, ctxt, view:core.BNBinaryView, var:core.BNDataVariable) -> None: + def _data_var_updated(self, ctxt, view: core.BNBinaryView, var: core.BNDataVariable) -> None: try: self._notify.data_var_updated(self._view, DataVariable.from_core_struct(var[0], self._view)) except: log_error(traceback.format_exc()) - def _data_metadata_updated(self, ctxt, view:core.BNBinaryView, offset:int) -> None: + def _data_metadata_updated(self, ctxt, view: core.BNBinaryView, offset: int) -> None: try: self._notify.data_metadata_updated(self._view, offset) except: log_error(traceback.format_exc()) - def _tag_type_updated(self, ctxt, view:core.BNBinaryView, tag_type:core.BNTagType) -> None: + def _tag_type_updated(self, ctxt, view: core.BNBinaryView, tag_type: core.BNTagType) -> None: try: core_tag_type = core.BNNewTagTypeReference(tag_type) assert core_tag_type is not None, "core.BNNewTagTypeReference returned None" @@ -501,7 +514,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _tag_added(self, ctxt, view:core.BNBinaryView, tag_ref:core.BNTagReference) -> None: + def _tag_added(self, ctxt, view: core.BNBinaryView, tag_ref: core.BNTagReference) -> None: try: ref_type = tag_ref[0].refType auto_defined = tag_ref[0].autoDefined @@ -512,7 +525,7 @@ class BinaryDataNotificationCallbacks: if ctypes.cast(tag_ref[0].arch, ctypes.c_void_p).value is None: arch = None else: - arch = architecture.CoreArchitecture._from_cache(tag_ref[0].arch) + arch = architecture.CoreArchitecture._from_cache(tag_ref[0].arch) if ctypes.cast(tag_ref[0].func, ctypes.c_void_p).value is None: func = None else: @@ -522,7 +535,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _tag_updated(self, ctxt, view:core.BNBinaryView, tag_ref:core.BNTagReference) -> None: + def _tag_updated(self, ctxt, view: core.BNBinaryView, tag_ref: core.BNTagReference) -> None: try: ref_type = tag_ref[0].refType auto_defined = tag_ref[0].autoDefined @@ -543,7 +556,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _tag_removed(self, ctxt, view:core.BNBinaryView, tag_ref:core.BNTagReference) -> None: + def _tag_removed(self, ctxt, view: core.BNBinaryView, tag_ref: core.BNTagReference) -> None: try: ref_type = tag_ref[0].refType auto_defined = tag_ref[0].autoDefined @@ -564,7 +577,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _symbol_added(self, ctxt, view:core.BNBinaryView, sym:core.BNSymbol) -> None: + def _symbol_added(self, ctxt, view: core.BNBinaryView, sym: core.BNSymbol) -> None: try: _handle = core.BNNewSymbolReference(sym) assert _handle is not None, "core.BNNewSymbolReference returned None" @@ -572,7 +585,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _symbol_updated(self, ctxt, view:core.BNBinaryView, sym:core.BNSymbol) -> None: + def _symbol_updated(self, ctxt, view: core.BNBinaryView, sym: core.BNSymbol) -> None: try: _handle = core.BNNewSymbolReference(sym) assert _handle is not None, "core.BNNewSymbolReference returned None" @@ -580,7 +593,7 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _symbol_removed(self, ctxt, view:core.BNBinaryView, sym:core.BNSymbol) -> None: + def _symbol_removed(self, ctxt, view: core.BNBinaryView, sym: core.BNSymbol) -> None: try: _handle = core.BNNewSymbolReference(sym) assert _handle is not None, "core.BNNewSymbolReference returned None" @@ -588,40 +601,49 @@ class BinaryDataNotificationCallbacks: except: log_error(traceback.format_exc()) - def _string_found(self, ctxt, view:core.BNBinaryView, string_type:int, offset:int, length:int) -> None: + def _string_found(self, ctxt, view: core.BNBinaryView, string_type: int, offset: int, length: int) -> None: try: self._notify.string_found(self._view, StringType(string_type), offset, length) except: log_error(traceback.format_exc()) - def _string_removed(self, ctxt, view:core.BNBinaryView, string_type:int, offset:int, length:int) -> None: + def _string_removed(self, ctxt, view: core.BNBinaryView, string_type: int, offset: int, length: int) -> None: try: self._notify.string_removed(self._view, StringType(string_type), offset, length) except: log_error(traceback.format_exc()) - def _type_defined(self, ctxt, view:core.BNBinaryView, name:str, type_obj:'_types.Type') -> None: + def _type_defined(self, ctxt, view: core.BNBinaryView, name: str, type_obj: '_types.Type') -> None: try: qualified_name = _types.QualifiedName._from_core_struct(name[0]) - self._notify.type_defined(self._view, qualified_name, _types.Type.create(core.BNNewTypeReference(type_obj), platform = self._view.platform)) + self._notify.type_defined( + self._view, qualified_name, + _types.Type.create(core.BNNewTypeReference(type_obj), platform=self._view.platform) + ) except: log_error(traceback.format_exc()) - def _type_undefined(self, ctxt, view:core.BNBinaryView, name:str, type_obj:'_types.Type') -> None: + def _type_undefined(self, ctxt, view: core.BNBinaryView, name: str, type_obj: '_types.Type') -> None: try: qualified_name = _types.QualifiedName._from_core_struct(name[0]) - self._notify.type_undefined(self._view, qualified_name, _types.Type.create(core.BNNewTypeReference(type_obj), platform = self._view.platform)) + self._notify.type_undefined( + self._view, qualified_name, + _types.Type.create(core.BNNewTypeReference(type_obj), platform=self._view.platform) + ) except: log_error(traceback.format_exc()) - def _type_ref_changed(self, ctxt, view:core.BNBinaryView, name:str, type_obj:'_types.Type') -> None: + def _type_ref_changed(self, ctxt, view: core.BNBinaryView, name: str, type_obj: '_types.Type') -> None: try: qualified_name = _types.QualifiedName._from_core_struct(name[0]) - self._notify.type_ref_changed(self._view, qualified_name, _types.Type.create(core.BNNewTypeReference(type_obj), platform = self._view.platform)) + self._notify.type_ref_changed( + self._view, qualified_name, + _types.Type.create(core.BNNewTypeReference(type_obj), platform=self._view.platform) + ) except: log_error(traceback.format_exc()) - def _type_field_ref_changed(self, ctxt, view:core.BNBinaryView, name:str, offset:int) -> None: + def _type_field_ref_changed(self, ctxt, view: core.BNBinaryView, name: str, offset: int) -> None: try: qualified_name = _types.QualifiedName._from_core_struct(name[0]) self._notify.type_field_ref_changed(self._view, qualified_name, offset) @@ -661,7 +683,8 @@ class _BinaryViewTypeMetaclass(type): class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): # Used to force Python callback objects to not get garbage collected _platform_recognizers = {} - def __init__(self, handle:core.BNBinaryViewTypeHandle): + + def __init__(self, handle: core.BNBinaryViewTypeHandle): _handle = core.BNBinaryViewTypeHandle self.handle = ctypes.cast(handle, _handle) @@ -696,13 +719,13 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): """returns if the BinaryViewType is deprecated (read-only)""" return core.BNIsBinaryViewTypeDeprecated(self.handle) - def create(self, data:'BinaryView') -> Optional['BinaryView']: + def create(self, data: 'BinaryView') -> Optional['BinaryView']: view = core.BNCreateBinaryViewOfType(self.handle, data.handle) if view is None: return None return BinaryView(file_metadata=data.file, handle=view) - def open(self, src:PathType, file_metadata:'filemetadata.FileMetadata'=None) -> Optional['BinaryView']: + def open(self, src: PathType, file_metadata: 'filemetadata.FileMetadata' = None) -> Optional['BinaryView']: """ ``open`` opens an instance of a particular BinaryViewType and returns it, or None if not possible. @@ -717,8 +740,9 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): return self.create(data) @classmethod - def get_view_of_file(cls, filename:PathType, update_analysis:bool=True, - progress_func:Optional[ProgressFuncType]=None) -> Optional['BinaryView']: + def get_view_of_file( + cls, filename: PathType, update_analysis: bool = True, progress_func: Optional[ProgressFuncType] = None + ) -> Optional['BinaryView']: """ ``get_view_of_file`` opens and returns the first available :py:class:`BinaryView`, excluding a Raw :py:class:`BinaryViewType` unless no other view is available @@ -761,15 +785,17 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): if isDatabase: bv = view.get_view_of_type("Raw") else: - bv = cls["Raw"].open(filename) # type: ignore + bv = cls["Raw"].open(filename) # type: ignore if bv is not None and update_analysis: bv.update_analysis_and_wait() return bv @classmethod - def get_view_of_file_with_options(cls, filename:str, update_analysis:Optional[bool]=True, - progress_func:Optional[ProgressFuncType]=None, options:Mapping[str, Any]={}) -> Optional['BinaryView']: + def get_view_of_file_with_options( + cls, filename: str, update_analysis: Optional[bool] = True, progress_func: Optional[ProgressFuncType] = None, + options: Mapping[str, Any] = {} + ) -> Optional['BinaryView']: """ ``get_view_of_file_with_options`` opens, generates default load options (which are overridable), and returns the first available \ :py:class:`BinaryView`. If no :py:class:`BinaryViewType` is available, then a ``Mapped`` :py:class:`BinaryViewType` is used to load \ @@ -834,7 +860,7 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): bvt = available if bvt is None: - bvt = cls["Mapped"] # type: ignore + bvt = cls["Mapped"] # type: ignore default_settings = settings.Settings(bvt.name + "_settings") default_settings.deserialize_schema(settings.Settings().serialize_schema()) @@ -858,7 +884,9 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): break if not arch_entry: arch_names = [entry['architecture'] for entry in arch_list if entry['architecture']] - raise Exception(f"Could not load any of: {options['files.universal.architecturePreference']} from Universal image. Entry not found! Available entries: {arch_names}") + raise Exception( + f"Could not load any of: {options['files.universal.architecturePreference']} from Universal image. Entry not found! Available entries: {arch_names}" + ) load_settings = settings.Settings(core.BNGetUniqueIdentifierString()) load_settings.deserialize_schema(arch_entry[0]['loadSchema']) @@ -893,22 +921,22 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): bv.update_analysis_and_wait() return bv - def parse(self, data:'BinaryView') -> Optional['BinaryView']: + def parse(self, data: 'BinaryView') -> Optional['BinaryView']: view = core.BNParseBinaryViewOfType(self, data.handle) if view is None: return None return BinaryView(file_metadata=data.file, handle=view) - def is_valid_for_data(self, data:'BinaryView') -> bool: + def is_valid_for_data(self, data: 'BinaryView') -> bool: return core.BNIsBinaryViewTypeValidForData(self.handle, data.handle) - def get_default_load_settings_for_data(self, data:'BinaryView') -> Optional['settings.Settings']: + def get_default_load_settings_for_data(self, data: 'BinaryView') -> Optional['settings.Settings']: load_settings = core.BNGetBinaryViewDefaultLoadSettingsForData(self.handle, data.handle) if load_settings is None: return None return settings.Settings(handle=load_settings) - def get_load_settings_for_data(self, data:'BinaryView') -> Optional['settings.Settings']: + def get_load_settings_for_data(self, data: 'BinaryView') -> Optional['settings.Settings']: view_handle = None if data is not None: view_handle = data.handle @@ -917,27 +945,27 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): return None return settings.Settings(handle=load_settings) - def register_arch(self, ident:int, endian:Endianness, arch:'architecture.Architecture') -> None: + def register_arch(self, ident: int, endian: Endianness, arch: 'architecture.Architecture') -> None: core.BNRegisterArchitectureForViewType(self.handle, ident, endian, arch.handle) - def get_arch(self, ident:int, endian:Endianness) -> Optional['architecture.Architecture']: + def get_arch(self, ident: int, endian: Endianness) -> Optional['architecture.Architecture']: arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) if arch is None: return None return architecture.CoreArchitecture._from_cache(arch) - def register_platform(self, ident:int, arch:'architecture.Architecture', plat:'_platform.Platform') -> None: + def register_platform(self, ident: int, arch: 'architecture.Architecture', plat: '_platform.Platform') -> None: core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) - def register_default_platform(self, arch:'architecture.Architecture', plat:'_platform.Platform') -> None: + def register_default_platform(self, arch: 'architecture.Architecture', plat: '_platform.Platform') -> None: core.BNRegisterDefaultPlatformForViewType(self.handle, arch.handle, plat.handle) def register_platform_recognizer(self, ident, endian, cb): def callback(cb, view, meta): try: - file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) - meta_obj = metadata.Metadata(handle = core.BNNewMetadataReference(meta)) + file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) + view_obj = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) + meta_obj = metadata.Metadata(handle=core.BNNewMetadataReference(meta)) plat = cb(view_obj, meta_obj) if plat: handle = core.BNNewPlatformReference(plat.handle) @@ -947,25 +975,26 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): binaryninja.log_error(traceback.format_exc()) return None - callback_obj = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMetadata))(lambda ctxt, view, meta: callback(cb, view, meta)) + callback_obj = ctypes.CFUNCTYPE( + ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMetadata) + )(lambda ctxt, view, meta: callback(cb, view, meta)) core.BNRegisterPlatformRecognizerForViewType(self.handle, ident, endian, callback_obj, None) self.__class__._platform_recognizers[len(self.__class__._platform_recognizers)] = callback_obj - - def get_platform(self, ident:int, arch:'architecture.Architecture') -> Optional['_platform.Platform']: + def get_platform(self, ident: int, arch: 'architecture.Architecture') -> Optional['_platform.Platform']: plat = core.BNGetPlatformForViewType(self.handle, ident, arch.handle) if plat is None: return None - return _platform.Platform(handle = plat) + return _platform.Platform(handle=plat) def recognize_platform(self, ident, endian, view, metadata): plat = core.BNRecognizePlatformForViewType(self.handle, ident, endian, view.handle, metadata.handle) if plat is None: return None - return binaryninja.platform.Platform(handle = plat) + return binaryninja.platform.Platform(handle=plat) @staticmethod - def add_binaryview_finalized_event(callback:BinaryViewEvent.BinaryViewEventCallback) -> None: + def add_binaryview_finalized_event(callback: BinaryViewEvent.BinaryViewEventCallback) -> None: """ `add_binaryview_finalized_event` adds a callback that gets executed when new binaryview is finalized. @@ -974,7 +1003,7 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): BinaryViewEvent.register(BinaryViewEventType.BinaryViewFinalizationEvent, callback) @staticmethod - def add_binaryview_initial_analysis_completion_event(callback:BinaryViewEvent.BinaryViewEventCallback) -> None: + def add_binaryview_initial_analysis_completion_event(callback: BinaryViewEvent.BinaryViewEventCallback) -> None: """ `add_binaryview_initial_analysis_completion_event` adds a callback that gets executed after the initial analysis, as well as linear @@ -985,7 +1014,7 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): class Segment: - def __init__(self, handle:core.BNSegmentHandle): + def __init__(self, handle: core.BNSegmentHandle): self.handle = handle def __del__(self): @@ -993,9 +1022,9 @@ class Segment: core.BNFreeSegment(self.handle) def __repr__(self): - r ="r" if self.readable else "-" - w ="w" if self.writable else "-" - x ="x" if self.executable else "-" + r = "r" if self.readable else "-" + w = "w" if self.writable else "-" + x = "x" if self.executable else "-" return f"" def __len__(self): @@ -1014,7 +1043,7 @@ class Segment: def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) - def __contains__(self, i:int): + def __contains__(self, i: int): return i >= self.start and i < self.end @property @@ -1069,7 +1098,7 @@ class Segment: finally: core.BNFreeRelocationRanges(ranges) - def relocation_ranges_at(self, addr:int) -> List[Tuple[int, int]]: + def relocation_ranges_at(self, addr: int) -> List[Tuple[int, int]]: """List of relocation range tuples (read-only)""" count = ctypes.c_ulonglong() @@ -1082,7 +1111,7 @@ class Segment: class Section: - def __init__(self, handle:core.BNSectionHandle): + def __init__(self, handle: core.BNSectionHandle): self.handle = handle def __del__(self): @@ -1108,7 +1137,7 @@ class Section: def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) - def __contains__(self, i:int): + def __contains__(self, i: int): return i >= self.start and i < self.end @property @@ -1155,13 +1184,13 @@ class Section: def end(self) -> int: return self.start + len(self) - def range_contains_relocation(self, addr:int, size:int) -> bool: + def range_contains_relocation(self, addr: int, size: int) -> bool: """Checks if the specified range overlaps with a relocation""" return core.BNSegmentRangeContainsRelocation(self.handle, addr, size) class TagType: - def __init__(self, handle:core.BNTagTypeHandle): + def __init__(self, handle: core.BNTagTypeHandle): self.handle = handle def __del__(self): @@ -1195,7 +1224,7 @@ class TagType: return core.BNTagTypeGetName(self.handle) @name.setter - def name(self, value:str) -> None: + def name(self, value: str) -> None: core.BNTagTypeSetName(self.handle, value) @property @@ -1204,7 +1233,7 @@ class TagType: return core.BNTagTypeGetIcon(self.handle) @icon.setter - def icon(self, value:str) -> None: + def icon(self, value: str) -> None: core.BNTagTypeSetIcon(self.handle, value) @property @@ -1213,7 +1242,7 @@ class TagType: return core.BNTagTypeGetVisible(self.handle) @visible.setter - def visible(self, value:bool) -> None: + def visible(self, value: bool) -> None: core.BNTagTypeSetVisible(self.handle, value) @property @@ -1222,12 +1251,12 @@ class TagType: return TagTypeType(core.BNTagTypeGetType(self.handle)) @type.setter - def type(self, value:TagTypeType) -> None: + def type(self, value: TagTypeType) -> None: core.BNTagTypeSetType(self.handle, value) class Tag: - def __init__(self, handle:core.BNTagHandle): + def __init__(self, handle: core.BNTagHandle): self.handle = handle def __del__(self): @@ -1265,7 +1294,7 @@ class Tag: return core.BNTagGetData(self.handle) @data.setter - def data(self, value:str) -> None: + def data(self, value: str) -> None: core.BNTagSetData(self.handle, value) @@ -1284,10 +1313,10 @@ class SymbolMapping(collections.abc.Mapping): # type: ignore >>> print("Found") """ - def __init__(self, view:'BinaryView'): + def __init__(self, view: 'BinaryView'): self._symbol_list = None self._count = None - self._symbol_cache:Optional[Mapping[bytes, List[_types.CoreSymbol]]] = None + self._symbol_cache: Optional[Mapping[bytes, List[_types.CoreSymbol]]] = None self._view = view self._n = 0 @@ -1384,10 +1413,10 @@ class TypeMapping(collections.abc.Mapping): # type: ignore >>> print("Found") """ - def __init__(self, view:'BinaryView'): + def __init__(self, view: 'BinaryView'): self._type_list = None self._count = None - self._type_cache:Optional[Mapping[_types.QualifiedName, _types.Type]] = None + self._type_cache: Optional[Mapping[_types.QualifiedName, _types.Type]] = None self._view = view def __repr__(self): @@ -1418,7 +1447,7 @@ class TypeMapping(collections.abc.Mapping): # type: ignore self._count = count.value for i in range(len(self)): name = _types.QualifiedName._from_core_struct(self._type_list[i].name) - type = _types.Type.create(core.BNNewTypeReference(self._type_list[i].type), platform = self._view.platform) + type = _types.Type.create(core.BNNewTypeReference(self._type_list[i].type), platform=self._view.platform) self._type_cache[name] = type yield name, type @@ -1442,7 +1471,7 @@ class TypeMapping(collections.abc.Mapping): # type: ignore return self.view == other.view def __ne__(self, other): - return not(self == other) + return not (self == other) def keys(self): if self._type_cache is None: @@ -1470,7 +1499,7 @@ class TypeMapping(collections.abc.Mapping): # type: ignore class FunctionList: - def __init__(self, view:'BinaryView'): + def __init__(self, view: 'BinaryView'): count = ctypes.c_ulonglong(0) _funcs = core.BNGetAnalysisFunctionList(view.handle, count) assert _funcs is not None, "core.BNGetAnalysisFunctionList returned None" @@ -1491,7 +1520,7 @@ class FunctionList: self._n += 1 return _function.Function(self._view, func) - def __getitem__(self, i:Union[int, slice]) -> Union['_function.Function', List['_function.Function']]: + def __getitem__(self, i: Union[int, slice]) -> Union['_function.Function', List['_function.Function']]: if isinstance(i, int): if i < 0: i = len(self) + i @@ -1545,7 +1574,7 @@ class AdvancedILFunctionList: >>> timeit.timeit(lambda:[f for f in bv.functions], number=1) 0.02230275600004461 """ - def __init__(self, view:'BinaryView', preload_limit:int = 5, functions:Optional[Iterable]=None): + def __init__(self, view: 'BinaryView', preload_limit: int = 5, functions: Optional[Iterable] = None): self._view = view self._func_queue = deque() self._preload_limit = preload_limit @@ -1614,13 +1643,17 @@ class BinaryView: to the database is desired. """ name: Optional[str] = None - long_name: Optional[str] = None + long_name: Optional[str] = None _registered = False _registered_cb = None registered_view_type = None _associated_data = {} _registered_instances = [] - def __init__(self, file_metadata:'filemetadata.FileMetadata'=None, parent_view:'BinaryView'=None, handle:core.BNBinaryViewHandle=None): + + def __init__( + self, file_metadata: 'filemetadata.FileMetadata' = None, parent_view: 'BinaryView' = None, + handle: core.BNBinaryViewHandle = None + ): if handle is not None: _handle = handle if file_metadata is None: @@ -1785,7 +1818,7 @@ class BinaryView: else: raise IndexError("index out of range") - def __contains__(self, i:int): + def __contains__(self, i: int): for s in self.segments: if i in s: return True @@ -1803,7 +1836,9 @@ class BinaryView: cls._registered_cb.create = cls._registered_cb.create.__class__(cls._create) cls._registered_cb.parse = cls._registered_cb.parse.__class__(cls._parse) cls._registered_cb.isValidForData = cls._registered_cb.isValidForData.__class__(cls._is_valid_for_data) - cls._registered_cb.getLoadSettingsForData = cls._registered_cb.getLoadSettingsForData.__class__(cls._get_load_settings_for_data) + cls._registered_cb.getLoadSettingsForData = cls._registered_cb.getLoadSettingsForData.__class__( + cls._get_load_settings_for_data + ) view_handle = core.BNRegisterBinaryViewType(cls.name, cls.long_name, cls._registered_cb) assert view_handle is not None, "core.BNRegisterBinaryViewType returned None" cls.registered_view_type = BinaryViewType(view_handle) @@ -1814,14 +1849,14 @@ class BinaryView: return self._parse_only @parse_only.setter - def parse_only(self, value:bool) -> None: + def parse_only(self, value: bool) -> None: self._parse_only = value @classmethod - def _create(cls, ctxt, data:core.BNBinaryView): + def _create(cls, ctxt, data: core.BNBinaryView): try: file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(data)) - view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data))) # type: ignore + view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data))) # type: ignore if view is None: return None view.parse_only = False @@ -1833,10 +1868,10 @@ class BinaryView: return None @classmethod - def _parse(cls, ctxt, data:core.BNBinaryView): + def _parse(cls, ctxt, data: core.BNBinaryView): try: file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(data)) - view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data))) # type: ignore + view = cls(BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(data))) # type: ignore if view is None: return None view.parse_only = True @@ -1851,7 +1886,7 @@ class BinaryView: def _is_valid_for_data(cls, ctxt, data): try: # I'm not sure whats going on here even so I've suppressed the linter warning - return cls.is_valid_for_data(BinaryView(handle=core.BNNewViewReference(data))) # type: ignore + return cls.is_valid_for_data(BinaryView(handle=core.BNNewViewReference(data))) # type: ignore except: log_error(traceback.format_exc()) return False @@ -1861,7 +1896,9 @@ class BinaryView: try: attr = getattr(cls, "get_load_settings_for_data", None) if callable(attr): - result = cls.get_load_settings_for_data(BinaryView(handle=core.BNNewViewReference(data))) # type: ignore + result = cls.get_load_settings_for_data( + BinaryView(handle=core.BNNewViewReference(data)) + ) # type: ignore settings_handle = core.BNNewSettingsReference(result.handle) assert settings_handle is not None, "core.BNNewSettingsReference returned None" return ctypes.cast(settings_handle, ctypes.c_void_p).value @@ -1887,7 +1924,7 @@ class BinaryView: return BinaryView(file_metadata=file_metadata, handle=view) @staticmethod - def new(data:bytes=None, file_metadata:Optional['filemetadata.FileMetadata']=None) -> Optional['BinaryView']: + def new(data: bytes = None, file_metadata: Optional['filemetadata.FileMetadata'] = None) -> Optional['BinaryView']: binaryninja._init_plugins() if file_metadata is None: file_metadata = filemetadata.FileMetadata() @@ -1901,13 +1938,13 @@ class BinaryView: return BinaryView(file_metadata=file_metadata, handle=view) @classmethod - def _unregister(cls, view:core.BNBinaryView) -> None: + def _unregister(cls, view: core.BNBinaryView) -> None: handle = ctypes.cast(view, ctypes.c_void_p) if handle.value in cls._associated_data: del cls._associated_data[handle.value] @staticmethod - def set_default_session_data(name:str, value:str) -> None: + def set_default_session_data(name: str, value: str) -> None: """ ``set_default_session_data`` saves a variable to the BinaryView. @@ -1926,7 +1963,7 @@ class BinaryView: return self._preload_limit @preload_limit.setter - def preload_limit(self, value:int) -> None: + def preload_limit(self, value: int) -> None: self._preload_limit = value @property @@ -1948,7 +1985,7 @@ class BinaryView: yield from func.basic_blocks @property - def hlil_basic_blocks(self) -> Generator['highlevelil.HighLevelILBasicBlock', None, None]: + def hlil_basic_blocks(self) -> Generator['highlevelil.HighLevelILBasicBlock', None, None]: """A generator of all HighLevelILBasicBlock objects in the BinaryView""" for func in self.hlil_functions(): yield from func.basic_blocks @@ -1994,7 +2031,7 @@ class BinaryView: return self._file.modified @modified.setter - def modified(self, value:bool) -> None: + def modified(self, value: bool) -> None: self._file.modified = value @property @@ -2012,7 +2049,7 @@ class BinaryView: return self._file.view @view.setter - def view(self, value:str) -> None: + def view(self, value: str) -> None: self._file.view = value @property @@ -2020,7 +2057,7 @@ class BinaryView: return self._file.offset @offset.setter - def offset(self, value:int) -> None: + def offset(self, value: int) -> None: self._file.offset = value @property @@ -2052,7 +2089,7 @@ class BinaryView: return architecture.CoreArchitecture._from_cache(handle=arch) @arch.setter - def arch(self, value:'architecture.Architecture') -> None: + def arch(self, value: 'architecture.Architecture') -> None: if value is None: core.BNSetDefaultArchitecture(self.handle, None) else: @@ -2067,7 +2104,7 @@ class BinaryView: return _platform.Platform(self.arch, handle=plat) @platform.setter - def platform(self, value:Optional['_platform.Platform']) -> None: + def platform(self, value: Optional['_platform.Platform']) -> None: if value is None: core.BNSetDefaultPlatform(self.handle, None) else: @@ -2098,20 +2135,30 @@ class BinaryView: """returns a FunctionList object (read-only)""" return FunctionList(self) - def mlil_functions(self, preload_limit:Optional[int] = None, function_generator:Generator['_function.Function', None, None] = None) -> Generator['mediumlevelil.MediumLevelILFunction', None, None]: + def mlil_functions( + self, preload_limit: Optional[int] = None, function_generator: Generator['_function.Function', None, + None] = None + ) -> Generator['mediumlevelil.MediumLevelILFunction', None, None]: """ Generates a list of il functions. This method should be used instead of 'functions' property if MLIL is needed and performance is a concern. """ - for func in AdvancedILFunctionList(self, self.preload_limit if preload_limit is None else preload_limit, function_generator): + for func in AdvancedILFunctionList( + self, self.preload_limit if preload_limit is None else preload_limit, function_generator + ): yield func.mlil - def hlil_functions(self, preload_limit:Optional[int] = None, function_generator:Generator['_function.Function', None, None] = None) -> Generator['highlevelil.HighLevelILFunction', None, None]: + def hlil_functions( + self, preload_limit: Optional[int] = None, function_generator: Generator['_function.Function', None, + None] = None + ) -> Generator['highlevelil.HighLevelILFunction', None, None]: """ Generates a list of il functions. This method should be used instead of 'functions' property if HLIL is needed and performance is a concern. """ - for func in AdvancedILFunctionList(self, self.preload_limit if preload_limit is None else preload_limit, function_generator): + for func in AdvancedILFunctionList( + self, self.preload_limit if preload_limit is None else preload_limit, function_generator + ): yield func.hlil @property @@ -2211,7 +2258,7 @@ class BinaryView: return self._file.saved @saved.setter - def saved(self, value:bool) -> None: + def saved(self, value: bool) -> None: self._file.saved = value @property @@ -2228,11 +2275,14 @@ class BinaryView: info_ref = core.BNGetAnalysisInfo(self.handle) assert info_ref is not None, "core.BNGetAnalysisInfo returned None" info = info_ref[0] - active_info_list:List[ActiveAnalysisInfo] = [] + active_info_list: List[ActiveAnalysisInfo] = [] try: for i in range(0, info.count): func = _function.Function(self, core.BNNewFunctionReference(info.activeInfo[i].func)) - active_info = ActiveAnalysisInfo(func, info.activeInfo[i].analysisTime, info.activeInfo[i].updateCount, info.activeInfo[i].submitCount) + active_info = ActiveAnalysisInfo( + func, info.activeInfo[i].analysisTime, info.activeInfo[i].updateCount, + info.activeInfo[i].submitCount + ) active_info_list.append(active_info) return AnalysisInfo(info.state, info.analysisTime, active_info_list) finally: @@ -2281,7 +2331,6 @@ class BinaryView: finally: core.BNFreeTypeNameList(name_list, count.value) - @property def type_libraries(self) -> List['typelibrary.TypeLibrary']: """List of imported type libraries (read-only)""" @@ -2296,7 +2345,6 @@ class BinaryView: finally: core.BNFreeTypeLibraryList(libraries, count.value) - @property def segments(self) -> List['Segment']: """List of segments (read-only)""" @@ -2374,7 +2422,7 @@ class BinaryView: return core.BNGetMaxFunctionSizeForAnalysis(self.handle) @max_function_size_for_analysis.setter - def max_function_size_for_analysis(self, size:int) -> None: + def max_function_size_for_analysis(self, size: int) -> None: core.BNSetMaxFunctionSizeForAnalysis(self.handle, size) @property @@ -2388,7 +2436,7 @@ class BinaryView: finally: core.BNFreeRelocationRanges(ranges) - def relocation_ranges_at(self, addr:int) -> List[Tuple[int, int]]: + def relocation_ranges_at(self, addr: int) -> List[Tuple[int, int]]: """List of relocation range tuples for a given address""" count = ctypes.c_ulonglong() @@ -2399,7 +2447,7 @@ class BinaryView: finally: core.BNFreeRelocationRanges(ranges) - def range_contains_relocation(self, addr:int, size:int) -> bool: + def range_contains_relocation(self, addr: int, size: int) -> bool: """Checks if the specified range overlaps with a relocation""" return core.BNRangeContainsRelocation(self.handle, addr, size) @@ -2409,7 +2457,7 @@ class BinaryView: return core.BNGetNewAutoFunctionAnalysisSuppressed(self.handle) @new_auto_function_analysis_suppressed.setter - def new_auto_function_analysis_suppressed(self, suppress:bool) -> None: + def new_auto_function_analysis_suppressed(self, suppress: bool) -> None: core.BNSetNewAutoFunctionAnalysisSuppressed(self.handle, suppress) def _init(self, ctxt): @@ -2570,7 +2618,9 @@ class BinaryView: def init(self) -> bool: return True - def disassembly_tokens(self, addr:int, arch:Optional['architecture.Architecture']=None) -> Generator[Tuple[List['_function.InstructionTextToken'], int], None, None]: + def disassembly_tokens( + self, addr: int, arch: Optional['architecture.Architecture'] = None + ) -> Generator[Tuple[List['_function.InstructionTextToken'], int], None, None]: if arch is None: if self.arch is None: raise Exception("Can not call method disassembly with no Architecture specified") @@ -2584,7 +2634,8 @@ class BinaryView: break yield (tokens, size) - def disassembly_text(self, addr:int, arch:Optional['architecture.Architecture']=None) -> Generator[Tuple[str, int], None, None]: + def disassembly_text(self, addr: int, + arch: Optional['architecture.Architecture'] = None) -> Generator[Tuple[str, int], None, None]: """ ``disassembly_text`` helper function for getting disassembly of a given address @@ -2611,7 +2662,7 @@ class BinaryView: break yield (''.join(str(a) for a in tokens).strip(), size) - def get_disassembly(self, addr:int, arch:Optional['architecture.Architecture']=None) -> Optional[str]: + def get_disassembly(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> Optional[str]: """ ``get_disassembly`` simple helper function for printing disassembly of a given address :param int addr: virtual address of instruction @@ -2659,7 +2710,7 @@ class BinaryView: """ return 0 - def perform_read(self, addr:int, length:int) -> bytes: + def perform_read(self, addr: int, length: int) -> bytes: """ ``perform_read`` implements a mapping between a virtual address and an absolute file offset, reading ``length`` bytes from the rebased address ``addr``. @@ -2676,7 +2727,7 @@ class BinaryView: """ return b"" - def perform_write(self, addr:int, data:bytes) -> int: + def perform_write(self, addr: int, data: bytes) -> int: """ ``perform_write`` implements a mapping between a virtual address and an absolute file offset, writing the bytes ``data`` to rebased address ``addr``. @@ -2693,7 +2744,7 @@ class BinaryView: """ return 0 - def perform_insert(self, addr:int, data:bytes) -> int: + def perform_insert(self, addr: int, data: bytes) -> int: """ ``perform_insert`` implements a mapping between a virtual address and an absolute file offset, inserting the bytes ``data`` to rebased address ``addr``. @@ -2709,7 +2760,7 @@ class BinaryView: """ return 0 - def perform_remove(self, addr:int, length:int) -> int: + def perform_remove(self, addr: int, length: int) -> int: """ ``perform_remove`` implements a mapping between a virtual address and an absolute file offset, removing ``length`` bytes from the rebased address ``addr``. @@ -2725,7 +2776,7 @@ class BinaryView: """ return 0 - def perform_get_modification(self, addr:int) -> ModificationStatus: + def perform_get_modification(self, addr: int) -> ModificationStatus: """ ``perform_get_modification`` implements query to the whether the virtual address ``addr`` is modified. @@ -2740,7 +2791,7 @@ class BinaryView: """ return ModificationStatus.Original - def perform_is_valid_offset(self, addr:int) -> bool: + def perform_is_valid_offset(self, addr: int) -> bool: """ ``perform_is_valid_offset`` implements a check if an virtual address ``addr`` is valid. @@ -2756,7 +2807,7 @@ class BinaryView: data = self.read(addr, 1) return (data is not None) and (len(data) == 1) - def perform_is_offset_readable(self, offset:int) -> bool: + def perform_is_offset_readable(self, offset: int) -> bool: """ ``perform_is_offset_readable`` implements a check if an virtual address is readable. @@ -2771,7 +2822,7 @@ class BinaryView: """ return self.is_valid_offset(offset) - def perform_is_offset_writable(self, addr:int) -> bool: + def perform_is_offset_writable(self, addr: int) -> bool: """ ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is writable. @@ -2786,7 +2837,7 @@ class BinaryView: """ return self.is_valid_offset(addr) - def perform_is_offset_executable(self, addr:int) -> bool: + def perform_is_offset_executable(self, addr: int) -> bool: """ ``perform_is_offset_executable`` implements a check if a virtual address ``addr`` is executable. @@ -2801,7 +2852,7 @@ class BinaryView: """ return self.is_valid_offset(addr) - def perform_get_next_valid_offset(self, addr:int) -> int: + def perform_get_next_valid_offset(self, addr: int) -> int: """ ``perform_get_next_valid_offset`` implements a query for the next valid readable, writable, or executable virtual memory address. @@ -2886,7 +2937,10 @@ class BinaryView: """ return False - def create_database(self, filename:str, progress_func:Optional[ProgressFuncType]=None, settings:Optional['filemetadata.SaveSettings']=None) -> bool: + def create_database( + self, filename: str, progress_func: Optional[ProgressFuncType] = None, + settings: Optional['filemetadata.SaveSettings'] = None + ) -> bool: """ ``create_database`` writes the current database (.bndb) out to the specified file. @@ -2902,7 +2956,9 @@ class BinaryView: """ return self._file.create_database(filename, progress_func, settings) - def save_auto_snapshot(self, progress_func:Optional[ProgressFuncType]=None, settings:Optional['filemetadata.SaveSettings']=None) -> bool: + def save_auto_snapshot( + self, progress_func: Optional[ProgressFuncType] = None, settings: Optional['filemetadata.SaveSettings'] = None + ) -> bool: """ ``save_auto_snapshot`` saves the current database to the already created file. @@ -2915,7 +2971,7 @@ class BinaryView: """ return self._file.save_auto_snapshot(progress_func, settings) - def get_view_of_type(self, name:str) -> Optional['BinaryView']: + def get_view_of_type(self, name: str) -> Optional['BinaryView']: """ ``get_view_of_type`` returns the BinaryView associated with the provided name if it exists. @@ -3019,7 +3075,7 @@ class BinaryView: """ self._file.redo() - def navigate(self, view_name:str, offset:int) -> bool: + def navigate(self, view_name: str, offset: int) -> bool: """ ``navigate`` navigates the UI to the specified virtual address @@ -3037,7 +3093,7 @@ class BinaryView: """ return self._file.navigate(view_name, offset) - def read(self, addr:int, length:int) -> bytes: + def read(self, addr: int, length: int) -> bytes: """ ``read`` returns the data reads at most ``length`` bytes from virtual address ``addr``. @@ -3060,7 +3116,7 @@ class BinaryView: buf = databuffer.DataBuffer(handle=core.BNReadViewBuffer(self.handle, addr, length)) return bytes(buf) - def read_int(self, address:int, size:int, sign:bool=True, endian:Optional[Endianness]=None) -> int: + def read_int(self, address: int, size: int, sign: bool = True, endian: Optional[Endianness] = None) -> int: _endian = self.endianness if endian is not None: _endian = endian @@ -3069,7 +3125,7 @@ class BinaryView: raise ValueError(f"Couldn't read {size} bytes from address: {address:#x}") return TypedDataAccessor.int_from_bytes(data, size, sign, _endian) - def read_pointer(self, address:int, size=None) -> int: + def read_pointer(self, address: int, size=None) -> int: _size = size if size is None: if self.arch is None: @@ -3077,7 +3133,7 @@ class BinaryView: _size = self.arch.address_size return self.read_int(address, _size, False, self.endianness) - def write(self, addr:int, data:bytes, except_on_relocation:bool = True) -> int: + def write(self, addr: int, data: bytes, except_on_relocation: bool = True) -> int: """ ``write`` writes the bytes in ``data`` to the virtual address ``addr``. @@ -3103,7 +3159,7 @@ class BinaryView: return core.BNWriteViewBuffer(self.handle, addr, buf.handle) - def insert(self, addr:int, data:bytes) -> int: + def insert(self, addr: int, data: bytes) -> int: """ ``insert`` inserts the bytes in ``data`` to the virtual address ``addr``. @@ -3124,7 +3180,7 @@ class BinaryView: buf = databuffer.DataBuffer(data) return core.BNInsertViewBuffer(self.handle, addr, buf.handle) - def remove(self, addr:int, length:int) -> int: + def remove(self, addr: int, length: int) -> int: """ ``remove`` removes at most ``length`` bytes from virtual address ``addr``. @@ -3143,7 +3199,7 @@ class BinaryView: """ return core.BNRemoveViewData(self.handle, addr, length) - def get_entropy(self, addr:int, length:int, block_size:int=0) -> List[float]: + def get_entropy(self, addr: int, length: int, block_size: int = 0) -> List[float]: """ ``get_entropy`` returns the shannon entropy given the start ``addr``, ``length`` in bytes, and optionally in ``block_size`` chunks. @@ -3159,14 +3215,14 @@ class BinaryView: return result if block_size == 0: block_size = length - data = (ctypes.c_float * ((length // block_size) + 1))() + data = (ctypes.c_float * ((length//block_size) + 1))() length = core.BNGetEntropy(self.handle, addr, length, block_size, data) for i in range(0, length): result.append(float(data[i])) return result - def get_modification(self, addr:int, length:int=None) -> List[ModificationStatus]: + def get_modification(self, addr: int, length: int = None) -> List[ModificationStatus]: """ ``get_modification`` returns the modified bytes of up to ``length`` bytes from virtual address ``addr``, or if ``length`` is None returns the ModificationStatus. @@ -3182,7 +3238,7 @@ class BinaryView: length = core.BNGetModificationArray(self.handle, addr, data, length) return [ModificationStatus(a) for a in data[:length]] - def is_valid_offset(self, addr:int) -> bool: + def is_valid_offset(self, addr: int) -> bool: """ ``is_valid_offset`` checks if an virtual address ``addr`` is valid . @@ -3192,7 +3248,7 @@ class BinaryView: """ return core.BNIsValidOffset(self.handle, addr) - def is_offset_readable(self, addr:int) -> bool: + def is_offset_readable(self, addr: int) -> bool: """ ``is_offset_readable`` checks if an virtual address ``addr`` is valid for reading. @@ -3202,7 +3258,7 @@ class BinaryView: """ return core.BNIsOffsetReadable(self.handle, addr) - def is_offset_writable(self, addr:int) -> bool: + def is_offset_writable(self, addr: int) -> bool: """ ``is_offset_writable`` checks if an virtual address ``addr`` is valid for writing. @@ -3212,7 +3268,7 @@ class BinaryView: """ return core.BNIsOffsetWritable(self.handle, addr) - def is_offset_executable(self, addr:int) -> bool: + def is_offset_executable(self, addr: int) -> bool: """ ``is_offset_executable`` checks if an virtual address ``addr`` is valid for executing. @@ -3222,7 +3278,7 @@ class BinaryView: """ return core.BNIsOffsetExecutable(self.handle, addr) - def is_offset_code_semantics(self, addr:int) -> bool: + def is_offset_code_semantics(self, addr: int) -> bool: """ ``is_offset_code_semantics`` checks if an virtual address ``addr`` is semantically valid for code. @@ -3232,7 +3288,7 @@ class BinaryView: """ return core.BNIsOffsetCodeSemantics(self.handle, addr) - def is_offset_extern_semantics(self, addr:int) -> bool: + def is_offset_extern_semantics(self, addr: int) -> bool: """ ``is_offset_extern_semantics`` checks if an virtual address ``addr`` is semantically valid for external references. @@ -3242,7 +3298,7 @@ class BinaryView: """ return core.BNIsOffsetExternSemantics(self.handle, addr) - def is_offset_writable_semantics(self, addr:int) -> bool: + def is_offset_writable_semantics(self, addr: int) -> bool: """ ``is_offset_writable_semantics`` checks if an virtual address ``addr`` is semantically writable. Some sections may have writable permissions for linking purposes but can be treated as read-only for the purposes of @@ -3254,7 +3310,7 @@ class BinaryView: """ return core.BNIsOffsetWritableSemantics(self.handle, addr) - def save(self, dest:Union['fileaccessor.FileAccessor', str]) -> bool: + def save(self, dest: Union['fileaccessor.FileAccessor', str]) -> bool: """ ``save`` saves the original binary file to the provided destination ``dest`` along with any modifications. @@ -3266,7 +3322,7 @@ class BinaryView: return core.BNSaveToFile(self.handle, dest._cb) return core.BNSaveToFilename(self.handle, str(dest)) - def register_notification(self, notify:BinaryDataNotification) -> None: + def register_notification(self, notify: BinaryDataNotification) -> None: """ `register_notification` provides a mechanism for receiving callbacks for various analysis events. A full list of callbacks can be seen in :py:Class:`BinaryDataNotification`. @@ -3278,7 +3334,7 @@ class BinaryView: cb._register() self._notifications[notify] = cb - def unregister_notification(self, notify:BinaryDataNotification) -> None: + def unregister_notification(self, notify: BinaryDataNotification) -> None: """ `unregister_notification` unregisters the :py:Class:`BinaryDataNotification` object passed to `register_notification` @@ -3290,7 +3346,7 @@ class BinaryView: self._notifications[notify]._unregister() del self._notifications[notify] - def add_function(self, addr:int, plat:Optional['_platform.Platform']=None) -> None: + def add_function(self, addr: int, plat: Optional['_platform.Platform'] = None) -> None: """ ``add_function`` add a new function of the given ``plat`` at the virtual address ``addr`` @@ -3312,7 +3368,7 @@ class BinaryView: raise AttributeError("Provided platform is not of type `Platform`") core.BNAddFunctionForAnalysis(self.handle, plat.handle, addr) - def add_entry_point(self, addr:int, plat:Optional['_platform.Platform']=None) -> None: + def add_entry_point(self, addr: int, plat: Optional['_platform.Platform'] = None) -> None: """ ``add_entry_point`` adds an virtual address to start analysis from for a given plat. @@ -3331,7 +3387,7 @@ class BinaryView: raise AttributeError("Provided platform is not of type `Platform`") core.BNAddEntryPointForAnalysis(self.handle, plat.handle, addr) - def remove_function(self, func:'_function.Function') -> None: + def remove_function(self, func: '_function.Function') -> None: """ ``remove_function`` removes the function ``func`` from the list of functions @@ -3349,7 +3405,7 @@ class BinaryView: """ core.BNRemoveAnalysisFunction(self.handle, func.handle) - def create_user_function(self, addr:int, plat:Optional['_platform.Platform']=None) -> '_function.Function': + def create_user_function(self, addr: int, plat: Optional['_platform.Platform'] = None) -> '_function.Function': """ ``create_user_function`` add a new *user* function of the given ``plat`` at the virtual address ``addr`` @@ -3369,7 +3425,7 @@ class BinaryView: plat = self.platform return _function.Function(self, core.BNCreateUserFunction(self.handle, plat.handle, addr)) - def remove_user_function(self, func:'_function.Function') -> None: + def remove_user_function(self, func: '_function.Function') -> None: """ ``remove_user_function`` removes the function ``func`` from the list of functions as a user action. @@ -3387,7 +3443,7 @@ class BinaryView: """ core.BNRemoveUserFunction(self.handle, func.handle) - def add_analysis_option(self, name:str) -> None: + def add_analysis_option(self, name: str) -> None: """ ``add_analysis_option`` adds an analysis option. Analysis options elaborate the analysis phase. The user must start analysis by calling either :func:`update_analysis` or :func:`update_analysis_and_wait`. @@ -3411,7 +3467,7 @@ class BinaryView: """ return core.BNHasInitialAnalysis(self.handle) - def set_analysis_hold(self, enable:bool) -> None: + def set_analysis_hold(self, enable: bool) -> None: """ ``set_analysis_hold`` control the analysis hold for this BinaryView. Enabling analysis hold defers all future analysis updates, therefore causing :func:`update_analysis` or :func:`update_analysis_and_wait` to take no action. @@ -3452,7 +3508,9 @@ class BinaryView: """ core.BNAbortAnalysis(self.handle) - def define_data_var(self, addr:int, var_type:StringOrType, name:Optional[Union[str, '_types.CoreSymbol']]=None) -> None: + def define_data_var( + self, addr: int, var_type: StringOrType, name: Optional[Union[str, '_types.CoreSymbol']] = None + ) -> None: """ ``define_data_var`` defines a non-user data variable ``var_type`` at the virtual address ``addr``. @@ -3483,7 +3541,9 @@ class BinaryView: name = _types.Symbol(SymbolType.DataSymbol, addr, name) self.define_auto_symbol(name) - def define_user_data_var(self, addr:int, var_type:StringOrType, name:Optional[Union[str, '_types.CoreSymbol']]=None) -> Optional['DataVariable']: + def define_user_data_var( + self, addr: int, var_type: StringOrType, name: Optional[Union[str, '_types.CoreSymbol']] = None + ) -> Optional['DataVariable']: """ ``define_user_data_var`` defines a user data variable ``var_type`` at the virtual address ``addr``. @@ -3518,7 +3578,7 @@ class BinaryView: return self.get_data_var_at(addr) - def undefine_data_var(self, addr:int) -> None: + def undefine_data_var(self, addr: int) -> None: """ ``undefine_data_var`` removes the non-user data variable at the virtual address ``addr``. @@ -3531,7 +3591,7 @@ class BinaryView: """ core.BNUndefineDataVariable(self.handle, addr) - def undefine_user_data_var(self, addr:int) -> None: + def undefine_user_data_var(self, addr: int) -> None: """ ``undefine_user_data_var`` removes the user data variable at the virtual address ``addr``. @@ -3544,7 +3604,7 @@ class BinaryView: """ core.BNUndefineUserDataVariable(self.handle, addr) - def get_data_var_at(self, addr:int) -> Optional['DataVariable']: + def get_data_var_at(self, addr: int) -> Optional['DataVariable']: """ ``get_data_var_at`` returns the data type at a given virtual address. @@ -3564,7 +3624,8 @@ class BinaryView: return None return DataVariable.from_core_struct(var, self) - def get_functions_containing(self, addr:int, plat:Optional['_platform.Platform']=None) -> List['_function.Function']: + def get_functions_containing(self, addr: int, + plat: Optional['_platform.Platform'] = None) -> List['_function.Function']: """ ``get_functions_containing`` returns a list of functions which contain the given address. @@ -3584,7 +3645,9 @@ class BinaryView: finally: core.BNFreeFunctionList(funcs, count.value) - def get_functions_by_name(self, name:str, plat:Optional['_platform.Platform']=None, ordered_filter:Optional[List[SymbolType]]=None) -> List['_function.Function']: + def get_functions_by_name( + self, name: str, plat: Optional['_platform.Platform'] = None, ordered_filter: Optional[List[SymbolType]] = None + ) -> List['_function.Function']: """``get_functions_by_name`` returns a list of Function objects function with a Symbol of ``name``. @@ -3600,9 +3663,9 @@ class BinaryView: >>> """ if ordered_filter is None: - ordered_filter = [SymbolType.FunctionSymbol, - SymbolType.ImportedFunctionSymbol, - SymbolType.LibraryFunctionSymbol] + ordered_filter = [ + SymbolType.FunctionSymbol, SymbolType.ImportedFunctionSymbol, SymbolType.LibraryFunctionSymbol + ] if plat == None: plat = self.platform @@ -3616,7 +3679,7 @@ class BinaryView: fns.append(fn) return fns - def get_function_at(self, addr:int, plat:Optional['_platform.Platform']=None) -> Optional['_function.Function']: + def get_function_at(self, addr: int, plat: Optional['_platform.Platform'] = None) -> Optional['_function.Function']: """ ``get_function_at`` gets a Function object for the function that starts at virtual address ``addr``: @@ -3644,7 +3707,7 @@ class BinaryView: return None return _function.Function(self, func) - def get_functions_at(self, addr:int) -> List['_function.Function']: + def get_functions_at(self, addr: int) -> List['_function.Function']: """ ``get_functions_at`` get a list of binaryninja.Function objects (one for each valid platform) that start at the @@ -3670,13 +3733,13 @@ class BinaryView: finally: core.BNFreeFunctionList(funcs, count.value) - def get_recent_function_at(self, addr:int) -> Optional['_function.Function']: + def get_recent_function_at(self, addr: int) -> Optional['_function.Function']: func = core.BNGetRecentAnalysisFunctionForAddress(self.handle, addr) if func is None: return None return _function.Function(self, func) - def get_basic_blocks_at(self, addr:int) -> List['basicblock.BasicBlock']: + def get_basic_blocks_at(self, addr: int) -> List['basicblock.BasicBlock']: """ ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which exist at the provided virtual address. @@ -3697,7 +3760,7 @@ class BinaryView: finally: core.BNFreeBasicBlockList(blocks, count.value) - def get_basic_blocks_starting_at(self, addr:int) -> List['basicblock.BasicBlock']: + def get_basic_blocks_starting_at(self, addr: int) -> List['basicblock.BasicBlock']: """ ``get_basic_blocks_starting_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address. @@ -3718,13 +3781,13 @@ class BinaryView: finally: core.BNFreeBasicBlockList(blocks, count.value) - def get_recent_basic_block_at(self, addr:int) -> Optional['basicblock.BasicBlock']: + def get_recent_basic_block_at(self, addr: int) -> Optional['basicblock.BasicBlock']: block = core.BNGetRecentBasicBlockForAddress(self.handle, addr) if block is None: return None return basicblock.BasicBlock(block, self) - def get_code_refs(self, addr:int, length:int=None) -> Generator['ReferenceSource', None, None]: + def get_code_refs(self, addr: int, length: int = None) -> Generator['ReferenceSource', None, None]: """ ``get_code_refs`` returns a Generator[ReferenceSource] objects (xrefs or cross-references) that point to the provided virtual address. This function returns both autoanalysis ("auto") and user-specified ("user") xrefs. @@ -3755,7 +3818,10 @@ class BinaryView: finally: core.BNFreeCodeReferences(refs, count.value) - def get_code_refs_from(self, addr:int, func:Optional['_function.Function']=None, arch:Optional['architecture.Architecture']=None, length:Optional[int]=None) -> List[int]: + def get_code_refs_from( + self, addr: int, func: Optional['_function.Function'] = None, + arch: Optional['architecture.Architecture'] = None, length: Optional[int] = None + ) -> List[int]: """ ``get_code_refs_from`` returns a list of virtual addresses referenced by code in the function ``func``, of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from @@ -3791,7 +3857,7 @@ class BinaryView: core.BNFreeAddressList(refs) return result - def get_data_refs(self, addr:int, length:int=None) -> Generator[int, None, None]: + def get_data_refs(self, addr: int, length: int = None) -> Generator[int, None, None]: """ ``get_data_refs`` returns a list of virtual addresses of data which references ``addr``. Optionally specifying a length. When ``length`` is set ``get_data_refs`` returns the data which references in the range ``addr``-``addr``+``length``. @@ -3822,7 +3888,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs) - def get_data_refs_from(self, addr:int, length:int=None) -> Generator[int, None, None]: + def get_data_refs_from(self, addr: int, length: int = None) -> Generator[int, None, None]: """ ``get_data_refs_from`` returns a list of virtual addresses referenced by the address ``addr``. Optionally specifying a length. When ``length`` is set ``get_data_refs_from`` returns the data referenced in the range ``addr``-``addr``+``length``. @@ -3853,7 +3919,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs) - def get_code_refs_for_type(self, name:str) -> Generator[ReferenceSource, None, None]: + def get_code_refs_for_type(self, name: str) -> Generator[ReferenceSource, None, None]: """ ``get_code_refs_for_type`` returns a Generator[ReferenceSource] objects (xrefs or cross-references) that reference the provided QualifiedName. @@ -3878,8 +3944,8 @@ class BinaryView: finally: core.BNFreeCodeReferences(refs, count.value) - - def get_code_refs_for_type_field(self, name:str, offset:int) -> Generator['_types.TypeFieldReference', None, None]: + def get_code_refs_for_type_field(self, name: str, + offset: int) -> Generator['_types.TypeFieldReference', None, None]: """ ``get_code_refs_for_type`` returns a Generator[TypeFieldReference] objects (xrefs or cross-references) that reference the provided type field. @@ -3913,13 +3979,14 @@ class BinaryView: size = refs[i].size typeObj = None if refs[i].incomingType.type: - typeObj = _types.Type(core.BNNewTypeReference(refs[i].incomingType.type), - confidence = refs[i].incomingType.confidence) + typeObj = _types.Type( + core.BNNewTypeReference(refs[i].incomingType.type), confidence=refs[i].incomingType.confidence + ) yield _types.TypeFieldReference(func, arch, addr, size, typeObj) finally: core.BNFreeTypeFieldReferences(refs, count.value) - def get_data_refs_for_type(self, name:str) -> Generator[int, None, None]: + def get_data_refs_for_type(self, name: str) -> Generator[int, None, None]: """ ``get_data_refs_for_type`` returns a list of virtual addresses of data which references the type ``name``. Note, the returned addresses are the actual start of the queried type. For example, suppose there is a DataVariable @@ -3946,8 +4013,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs) - - def get_data_refs_for_type_field(self, name:'_types.QualifiedNameType', offset:int) -> List[int]: + def get_data_refs_for_type_field(self, name: '_types.QualifiedNameType', offset: int) -> List[int]: """ ``get_data_refs_for_type_field`` returns a list of virtual addresses of data which references the type ``name``. Note, the returned addresses are the actual start of the queried type field. For example, suppose there is a @@ -3977,8 +4043,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs) - - def get_type_refs_for_type(self, name:'_types.QualifiedNameType') -> List['_types.TypeReferenceSource']: + def get_type_refs_for_type(self, name: '_types.QualifiedNameType') -> List['_types.TypeReferenceSource']: """ ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided QualifiedName. @@ -4000,14 +4065,16 @@ class BinaryView: result = [] try: for i in range(0, count.value): - type_field = _types.TypeReferenceSource(_types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + type_field = _types.TypeReferenceSource( + _types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type + ) result.append(type_field) return result finally: core.BNFreeTypeReferences(refs, count.value) - - def get_type_refs_for_type_field(self, name:'_types.QualifiedNameType', offset:int) -> List['_types.TypeReferenceSource']: + def get_type_refs_for_type_field(self, name: '_types.QualifiedNameType', + offset: int) -> List['_types.TypeReferenceSource']: """ ``get_type_refs_for_type`` returns a list of TypeReferenceSource objects (xrefs or cross-references) that reference the provided type field. @@ -4030,13 +4097,18 @@ class BinaryView: result = [] try: for i in range(0, count.value): - type_field = _types.TypeReferenceSource(_types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + type_field = _types.TypeReferenceSource( + _types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type + ) result.append(type_field) return result finally: core.BNFreeTypeReferences(refs, count.value) - def get_code_refs_for_type_from(self, addr:int, func:Optional['_function.Function']=None, arch:Optional['architecture.Architecture']= None, length:Optional[int] = None) -> List['_types.TypeReferenceSource']: + def get_code_refs_for_type_from( + self, addr: int, func: Optional['_function.Function'] = None, + arch: Optional['architecture.Architecture'] = None, length: Optional[int] = None + ) -> List['_types.TypeReferenceSource']: """ ``get_code_refs_for_type_from`` returns a list of types referenced by code in the function ``func``, of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from @@ -4065,13 +4137,18 @@ class BinaryView: assert refs is not None, "core.BNGetCodeReferencesForTypeFromInRange returned None" try: for i in range(0, count.value): - type_field = _types.TypeReferenceSource(_types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + type_field = _types.TypeReferenceSource( + _types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type + ) result.append(type_field) finally: core.BNFreeTypeReferences(refs, count.value) return result - def get_code_refs_for_type_fields_from(self, addr:int, func:Optional['_function.Function']=None, arch:Optional['architecture.Architecture']= None, length:Optional[int] = None) -> List['_types.TypeReferenceSource']: + def get_code_refs_for_type_fields_from( + self, addr: int, func: Optional['_function.Function'] = None, + arch: Optional['architecture.Architecture'] = None, length: Optional[int] = None + ) -> List['_types.TypeReferenceSource']: """ ``get_code_refs_for_type_fields_from`` returns a list of type fields referenced by code in the function ``func``, of the architecture ``arch``, and at the address ``addr``. If no function is specified, references from @@ -4100,13 +4177,15 @@ class BinaryView: assert refs is not None, "core.BNGetCodeReferencesForTypeFieldsFromInRange returned None" try: for i in range(0, count.value): - type_field = _types.TypeReferenceSource(_types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type) + type_field = _types.TypeReferenceSource( + _types.QualifiedName._from_core_struct(refs[i].name), refs[i].offset, refs[i].type + ) result.append(type_field) finally: core.BNFreeTypeReferences(refs, count.value) return result - def add_user_data_ref(self, from_addr:int, to_addr:int) -> None: + def add_user_data_ref(self, from_addr: int, to_addr: int) -> None: """ ``add_user_data_ref`` adds a user-specified data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``. If the reference already exists, no action is performed. To remove the reference, use :func:`remove_user_data_ref`. @@ -4117,8 +4196,7 @@ class BinaryView: """ core.BNAddUserDataReference(self.handle, from_addr, to_addr) - - def remove_user_data_ref(self, from_addr:int, to_addr:int) -> None: + def remove_user_data_ref(self, from_addr: int, to_addr: int) -> None: """ ``remove_user_data_ref`` removes a user-specified data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``. This function will only remove user-specified references, not ones generated during autoanalysis. @@ -4130,8 +4208,7 @@ class BinaryView: """ core.BNRemoveUserDataReference(self.handle, from_addr, to_addr) - - def get_all_fields_referenced(self, name:'_types.QualifiedNameType') -> List[int]: + def get_all_fields_referenced(self, name: '_types.QualifiedNameType') -> List[int]: """ ``get_all_fields_referenced`` returns a list of offsets in the QualifiedName specified by name, which are referenced by code. @@ -4159,7 +4236,7 @@ class BinaryView: finally: core.BNFreeDataReferences(refs) - def get_all_sizes_referenced(self, name:'_types.QualifiedNameType') -> Mapping[int, List[int]]: + def get_all_sizes_referenced(self, name: '_types.QualifiedNameType') -> Mapping[int, List[int]]: """ ``get_all_sizes_referenced`` returns a map from field offset to a list of sizes of the accesses to it. @@ -4178,7 +4255,7 @@ class BinaryView: _name = _types.QualifiedName(name)._to_core_struct() refs = core.BNGetAllSizesReferenced(self.handle, _name, count) assert refs is not None, "core.BNGetAllSizesReferenced returned None" - result:Mapping[int, List[int]] = {} + result: Mapping[int, List[int]] = {} try: for i in range(0, count.value): result[refs[i].offset] = [] @@ -4188,7 +4265,7 @@ class BinaryView: finally: core.BNFreeTypeFieldReferenceSizeInfo(refs, count.value) - def get_all_types_referenced(self, name:'_types.QualifiedNameType') -> Mapping[int, List['_types.Type']]: + def get_all_types_referenced(self, name: '_types.QualifiedNameType') -> Mapping[int, List['_types.Type']]: """ ``get_all_types_referenced`` returns a map from field offset to a related to the type field access. @@ -4209,19 +4286,20 @@ class BinaryView: refs = core.BNGetAllTypesReferenced(self.handle, _name, count) assert refs is not None, "core.BNGetAllTypesReferenced returned None" - result:Mapping[int, List['_types.Type']] = {} + result: Mapping[int, List['_types.Type']] = {} try: for i in range(0, count.value): result[refs[i].offset] = [] for j in range(0, refs[i].count): - typeObj = _types.Type.create(core.BNNewTypeReference(refs[i].types[j].type), - self.platform, refs[i].types[j].confidence) + typeObj = _types.Type.create( + core.BNNewTypeReference(refs[i].types[j].type), self.platform, refs[i].types[j].confidence + ) result[refs[i].offset].append(typeObj) return result finally: core.BNFreeTypeFieldReferenceTypeInfo(refs, count.value) - def get_sizes_referenced(self, name:'_types.QualifiedNameType', offset:int) -> List[int]: + def get_sizes_referenced(self, name: '_types.QualifiedNameType', offset: int) -> List[int]: """ ``get_sizes_referenced`` returns a list of sizes of the accesses to it. @@ -4249,7 +4327,7 @@ class BinaryView: finally: core.BNFreeTypeFieldReferenceSizes(refs, count.value) - def get_types_referenced(self, name:'_types.QualifiedName', offset:int) -> List['_types.Type']: + def get_types_referenced(self, name: '_types.QualifiedName', offset: int) -> List['_types.Type']: """ ``get_types_referenced`` returns a list of types related to the type field access. @@ -4270,14 +4348,13 @@ class BinaryView: try: result = [] for i in range(0, count.value): - typeObj = _types.Type.create(core.BNNewTypeReference(refs[i].type), - confidence = refs[i].confidence) + typeObj = _types.Type.create(core.BNNewTypeReference(refs[i].type), confidence=refs[i].confidence) result.append(typeObj) return result finally: core.BNFreeTypeFieldReferenceTypes(refs, count.value) - def create_structure_from_offset_access(self, name:'_types.QualifiedName') -> '_types.StructureType': + def create_structure_from_offset_access(self, name: '_types.QualifiedName') -> '_types.StructureType': newMemberAdded = ctypes.c_bool(False) _name = _types.QualifiedName(name)._to_core_struct() struct = core.BNCreateStructureFromOffsetAccess(self.handle, _name, newMemberAdded) @@ -4285,16 +4362,15 @@ class BinaryView: raise Exception("BNCreateStructureFromOffsetAccess failed to create struct from offsets") return _types.StructureType.from_core_struct(struct) - def create_structure_member_from_access(self, name:'_types.QualifiedName', offset:int) -> '_types.Type': + def create_structure_member_from_access(self, name: '_types.QualifiedName', offset: int) -> '_types.Type': _name = _types.QualifiedName(name)._to_core_struct() result = core.BNCreateStructureMemberFromAccess(self.handle, _name, offset) if not result.type: raise Exception("BNCreateStructureMemberFromAccess failed to create struct member offsets") - return _types.Type.create(core.BNNewTypeReference(result.type), - confidence = result.confidence) + return _types.Type.create(core.BNNewTypeReference(result.type), confidence=result.confidence) - def get_callers(self, addr:int) -> Generator[ReferenceSource, None, None]: + def get_callers(self, addr: int) -> Generator[ReferenceSource, None, None]: """ ``get_callers`` returns a list of ReferenceSource objects (xrefs or cross-references) that call the provided virtual address. In this case, tail calls, jumps, and ordinary calls are considered. @@ -4318,7 +4394,8 @@ class BinaryView: finally: core.BNFreeCodeReferences(refs, count.value) - def get_callees(self, addr:int, func:'_function.Function'=None, arch:'architecture.Architecture'=None) -> List[int]: + def get_callees(self, addr: int, func: '_function.Function' = None, + arch: 'architecture.Architecture' = None) -> List[int]: """ ``get_callees`` returns a list of virtual addresses called by the call site in the function ``func``, of the architecture ``arch``, and at the address ``addr``. If no function is specified, call sites from @@ -4350,7 +4427,7 @@ class BinaryView: core.BNFreeAddressList(refs) return result - def get_symbol_at(self, addr:int, namespace:'_types.NameSpaceType'=None) -> Optional['_types.CoreSymbol']: + def get_symbol_at(self, addr: int, namespace: '_types.NameSpaceType' = None) -> Optional['_types.CoreSymbol']: """ ``get_symbol_at`` returns the Symbol at the provided virtual address. @@ -4370,7 +4447,7 @@ class BinaryView: return None return _types.CoreSymbol(sym) - def get_symbols_by_raw_name(self, name:str, namespace:'_types.NameSpaceType'=None) -> List['_types.CoreSymbol']: + def get_symbols_by_raw_name(self, name: str, namespace: '_types.NameSpaceType' = None) -> List['_types.CoreSymbol']: _namespace = _types.NameSpace.get_core_struct(namespace) count = ctypes.c_ulonglong(0) syms = core.BNGetSymbolsByRawName(self.handle, name, count, _namespace) @@ -4385,7 +4462,8 @@ class BinaryView: finally: core.BNFreeSymbolList(syms, count.value) - def get_symbol_by_raw_name(self, name:str, namespace:'_types.NameSpaceType'=None) -> Optional['_types.CoreSymbol']: + def get_symbol_by_raw_name(self, name: str, + namespace: '_types.NameSpaceType' = None) -> Optional['_types.CoreSymbol']: """ ``get_symbol_by_raw_name`` retrieves a Symbol object for the given a raw (mangled) name. @@ -4405,7 +4483,9 @@ class BinaryView: return None return _types.CoreSymbol(sym) - def get_symbols_by_name(self, name:str, namespace:'_types.NameSpaceType'=None, ordered_filter:Optional[List[SymbolType]]=None) -> List['_types.CoreSymbol']: + def get_symbols_by_name( + self, name: str, namespace: '_types.NameSpaceType' = None, ordered_filter: Optional[List[SymbolType]] = None + ) -> List['_types.CoreSymbol']: """ ``get_symbols_by_name`` retrieves a list of Symbol objects for the given symbol name and ordered filter @@ -4422,13 +4502,11 @@ class BinaryView: >>> """ if ordered_filter is None: - ordered_filter = [SymbolType.FunctionSymbol, - SymbolType.ImportedFunctionSymbol, - SymbolType.LibraryFunctionSymbol, - SymbolType.DataSymbol, - SymbolType.ImportedDataSymbol, - SymbolType.ImportAddressSymbol, - SymbolType.ExternalSymbol] + ordered_filter = [ + SymbolType.FunctionSymbol, SymbolType.ImportedFunctionSymbol, SymbolType.LibraryFunctionSymbol, + SymbolType.DataSymbol, SymbolType.ImportedDataSymbol, SymbolType.ImportAddressSymbol, + SymbolType.ExternalSymbol + ] _namespace = _types.NameSpace.get_core_struct(namespace) count = ctypes.c_ulonglong(0) @@ -4440,12 +4518,16 @@ class BinaryView: handle = core.BNNewSymbolReference(syms[i]) assert handle is not None, "core.BNNewSymbolReference returned None" result.append(_types.CoreSymbol(handle)) - result = sorted(filter(lambda sym: sym.type in ordered_filter, result), key=lambda sym: ordered_filter.index(sym.type)) + result = sorted( + filter(lambda sym: sym.type in ordered_filter, result), key=lambda sym: ordered_filter.index(sym.type) + ) return result finally: core.BNFreeSymbolList(syms, count.value) - def get_symbols(self, start:Optional[int]=None, length:Optional[int]=None, namespace:'_types.NameSpaceType'=None) -> List['_types.CoreSymbol']: + def get_symbols( + self, start: Optional[int] = None, length: Optional[int] = None, namespace: '_types.NameSpaceType' = None + ) -> List['_types.CoreSymbol']: """ ``get_symbols`` retrieves the list of all Symbol objects in the optionally provided range. @@ -4479,8 +4561,10 @@ class BinaryView: finally: core.BNFreeSymbolList(syms, count.value) - def get_symbols_of_type(self, sym_type:SymbolType, start:Optional[int]=None, length:Optional[int]=None, - namespace:'_types.NameSpaceType'=None) -> List['_types.CoreSymbol']: + def get_symbols_of_type( + self, sym_type: SymbolType, start: Optional[int] = None, length: Optional[int] = None, + namespace: '_types.NameSpaceType' = None + ) -> List['_types.CoreSymbol']: """ ``get_symbols_of_type`` retrieves a list of all Symbol objects of the provided symbol type in the optionally provided range. @@ -4517,7 +4601,7 @@ class BinaryView: finally: core.BNFreeSymbolList(syms, count.value) - def define_auto_symbol(self, sym:'_types.CoreSymbol') -> None: + def define_auto_symbol(self, sym: '_types.CoreSymbol') -> None: """ ``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects in a given namespace. @@ -4529,8 +4613,9 @@ class BinaryView: """ core.BNDefineAutoSymbol(self.handle, sym.handle) - def define_auto_symbol_and_var_or_function(self, sym:'_types.CoreSymbol', sym_type:SymbolType, - plat:Optional['_platform.Platform']=None) -> Optional['_types.CoreSymbol']: + def define_auto_symbol_and_var_or_function( + self, sym: '_types.CoreSymbol', sym_type: SymbolType, plat: Optional['_platform.Platform'] = None + ) -> Optional['_types.CoreSymbol']: """ ``define_auto_symbol_and_var_or_function`` @@ -4558,7 +4643,7 @@ class BinaryView: return None return _types.CoreSymbol(_sym) - def undefine_auto_symbol(self, sym:'_types.CoreSymbol') -> None: + def undefine_auto_symbol(self, sym: '_types.CoreSymbol') -> None: """ ``undefine_auto_symbol`` removes a symbol from the internal list of automatically discovered Symbol objects. @@ -4567,7 +4652,7 @@ class BinaryView: """ core.BNUndefineAutoSymbol(self.handle, sym.handle) - def define_user_symbol(self, sym:'_types.CoreSymbol') -> None: + def define_user_symbol(self, sym: '_types.CoreSymbol') -> None: """ ``define_user_symbol`` adds a symbol to the internal list of user added Symbol objects. @@ -4578,7 +4663,7 @@ class BinaryView: """ core.BNDefineUserSymbol(self.handle, sym.handle) - def undefine_user_symbol(self, sym:'_types.CoreSymbol') -> None: + def undefine_user_symbol(self, sym: '_types.CoreSymbol') -> None: """ ``undefine_user_symbol`` removes a symbol from the internal list of user added Symbol objects. @@ -4587,7 +4672,9 @@ class BinaryView: """ core.BNUndefineUserSymbol(self.handle, sym.handle) - def define_imported_function(self, import_addr_sym:'_types.CoreSymbol', func:'_function.Function', type:Optional['_types.Type']=None) -> None: + def define_imported_function( + self, import_addr_sym: '_types.CoreSymbol', func: '_function.Function', type: Optional['_types.Type'] = None + ) -> None: """ ``define_imported_function`` defines an imported Function ``func`` with a ImportedFunctionSymbol type. @@ -4595,9 +4682,11 @@ class BinaryView: :param Function func: A Function object to define as an imported function :rtype: None """ - core.BNDefineImportedFunction(self.handle, import_addr_sym.handle, func.handle, None if type is None else type.handle) + core.BNDefineImportedFunction( + self.handle, import_addr_sym.handle, func.handle, None if type is None else type.handle + ) - def create_tag_type(self, name:str, icon:str) -> 'TagType': + def create_tag_type(self, name: str, icon: str) -> 'TagType': """ ``create_tag_type`` creates a new Tag Type and adds it to the view @@ -4619,7 +4708,7 @@ class BinaryView: core.BNAddTagType(self.handle, tag_type.handle) return tag_type - def remove_tag_type(self, tag_type:'TagType') -> None: + def remove_tag_type(self, tag_type: 'TagType') -> None: """ ``remove_tag_type`` removes a new Tag Type and all tags that use it @@ -4642,7 +4731,7 @@ class BinaryView: count = ctypes.c_ulonglong(0) types = core.BNGetTagTypes(self.handle, count) assert types is not None, "core.BNGetTagTypes returned None" - result:Mapping[str, Union['TagType', List['TagType']]] = {} + result: Mapping[str, Union['TagType', List['TagType']]] = {} try: for i in range(0, count.value): tag_handle = core.BNNewTagTypeReference(types[i]) @@ -4661,7 +4750,7 @@ class BinaryView: finally: core.BNFreeTagTypeList(types, count.value) - def get_tag_type(self, name:str) -> Optional['TagType']: + def get_tag_type(self, name: str) -> Optional['TagType']: """ Get a tag type by its name. Shorthand for get_tag_type_by_name() :param name: Name of the tag type @@ -4670,7 +4759,7 @@ class BinaryView: """ return self.get_tag_type_by_name(name) - def get_tag_type_by_name(self, name:str) -> Optional['TagType']: + def get_tag_type_by_name(self, name: str) -> Optional['TagType']: """ Get a tag type by its name :param name: Name of the tag type @@ -4682,7 +4771,7 @@ class BinaryView: return None return TagType(tag_type) - def get_tag_type_by_id(self, id:str) -> Optional['TagType']: + def get_tag_type_by_id(self, id: str) -> Optional['TagType']: """ Get a tag type by its id :param id: Id of the tag type @@ -4694,13 +4783,13 @@ class BinaryView: return None return TagType(tag_type) - def create_user_tag(self, type:'TagType', data:str) -> 'Tag': + def create_user_tag(self, type: 'TagType', data: str) -> 'Tag': return self.create_tag(type, data, True) - def create_auto_tag(self, type:'TagType', data:str) -> 'Tag': + def create_auto_tag(self, type: 'TagType', data: str) -> 'Tag': return self.create_tag(type, data, False) - def create_tag(self, tag_type:'TagType', data:str, user:bool=True) -> 'Tag': + def create_tag(self, tag_type: 'TagType', data: str, user: bool = True) -> 'Tag': """ ``create_tag`` creates a new Tag object but does not add it anywhere. Use :py:meth:`create_user_data_tag` to create and add in one step. @@ -4725,7 +4814,7 @@ class BinaryView: core.BNAddTag(self.handle, tag.handle, user) return tag - def get_tag(self, id:str) -> Optional['Tag']: + def get_tag(self, id: str) -> Optional['Tag']: """ Get a tag by its id. Note this does not tell you anything about where it is used. :param id: Tag id @@ -4807,7 +4896,7 @@ class BinaryView: finally: core.BNFreeTagReferences(refs, count.value) - def get_data_tags_at(self, addr:int) -> List['Tag']: + def get_data_tags_at(self, addr: int) -> List['Tag']: """ ``get_data_tags_at`` gets a list of all Tags for a data address. @@ -4828,7 +4917,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_auto_data_tags_at(self, addr:int) -> List['Tag']: + def get_auto_data_tags_at(self, addr: int) -> List['Tag']: """ ``get_auto_data_tags_at`` gets a list of all auto-defined Tags for a data address. @@ -4849,7 +4938,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_user_data_tags_at(self, addr:int) -> List['Tag']: + def get_user_data_tags_at(self, addr: int) -> List['Tag']: """ ``get_user_data_tags_at`` gets a list of all user Tags for a data address. @@ -4870,7 +4959,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_data_tags_of_type(self, addr:int, tag_type:'TagType') -> List['Tag']: + def get_data_tags_of_type(self, addr: int, tag_type: 'TagType') -> List['Tag']: """ ``get_data_tags_of_type`` gets a list of all Tags for a data address of a given type. @@ -4892,7 +4981,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_auto_data_tags_of_type(self, addr:int, tag_type:'TagType') -> List['Tag']: + def get_auto_data_tags_of_type(self, addr: int, tag_type: 'TagType') -> List['Tag']: """ ``get_auto_data_tags_of_type`` gets a list of all auto-defined Tags for a data address of a given type. @@ -4914,7 +5003,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_user_data_tags_of_type(self, addr:int, tag_type:'TagType') -> List['Tag']: + def get_user_data_tags_of_type(self, addr: int, tag_type: 'TagType') -> List['Tag']: """ ``get_user_data_tags_of_type`` gets a list of all user Tags for a data address of a given type. @@ -4936,7 +5025,7 @@ class BinaryView: finally: core.BNFreeTagList(tags, count.value) - def get_data_tags_in_range(self, address_range:'variable.AddressRange') -> List[Tuple[int, 'Tag']]: + def get_data_tags_in_range(self, address_range: 'variable.AddressRange') -> List[Tuple[int, 'Tag']]: """ ``get_data_tags_in_range`` gets a list of all data Tags in a given range. Range is inclusive at the start, exclusive at the end. @@ -4959,7 +5048,7 @@ class BinaryView: finally: core.BNFreeTagReferences(refs, count.value) - def get_auto_data_tags_in_range(self, address_range:'variable.AddressRange') -> List[Tuple[int, 'Tag']]: + def get_auto_data_tags_in_range(self, address_range: 'variable.AddressRange') -> List[Tuple[int, 'Tag']]: """ ``get_auto_data_tags_in_range`` gets a list of all auto-defined data Tags in a given range. Range is inclusive at the start, exclusive at the end. @@ -4982,7 +5071,7 @@ class BinaryView: finally: core.BNFreeTagReferences(refs, count.value) - def get_user_data_tags_in_range(self, address_range:'variable.AddressRange') -> List[Tuple[int, 'Tag']]: + def get_user_data_tags_in_range(self, address_range: 'variable.AddressRange') -> List[Tuple[int, 'Tag']]: """ ``get_user_data_tags_in_range`` gets a list of all user data Tags in a given range. Range is inclusive at the start, exclusive at the end. @@ -5005,7 +5094,7 @@ class BinaryView: finally: core.BNFreeTagReferences(refs, count.value) - def add_user_data_tag(self, addr:int, tag:'Tag') -> None: + def add_user_data_tag(self, addr: int, tag: 'Tag') -> None: """ ``add_user_data_tag`` adds an already-created Tag object at a data address. Since this adds a user tag, it will be added to the current undo buffer. @@ -5018,7 +5107,7 @@ class BinaryView: """ core.BNAddUserDataTag(self.handle, addr, tag.handle) - def create_user_data_tag(self, addr:int, type:'TagType', data:str, unique:bool=False) -> 'Tag': + def create_user_data_tag(self, addr: int, type: 'TagType', data: str, unique: bool = False) -> 'Tag': """ ``create_user_data_tag`` creates and adds a Tag object at a data address. Since this adds a user tag, it will be added to the current @@ -5050,7 +5139,7 @@ class BinaryView: core.BNAddUserDataTag(self.handle, addr, tag.handle) return tag - def remove_user_data_tag(self, addr:int, tag:Tag) -> None: + def remove_user_data_tag(self, addr: int, tag: Tag) -> None: """ ``remove_user_data_tag`` removes a Tag object at a data address. Since this removes a user tag, it will be added to the current undo buffer. @@ -5061,7 +5150,7 @@ class BinaryView: """ core.BNRemoveUserDataTag(self.handle, addr, tag.handle) - def remove_user_data_tags_of_type(self, addr:int, tag_type:'TagType') -> None: + def remove_user_data_tags_of_type(self, addr: int, tag_type: 'TagType') -> None: """ ``remove_user_data_tags_of_type`` removes all data tags at the given address of the given type. Since this removes user tags, it will be added to the current undo buffer. @@ -5072,7 +5161,7 @@ class BinaryView: """ core.BNRemoveUserDataTagsOfType(self.handle, addr, tag_type.handle) - def add_auto_data_tag(self, addr:int, tag:'Tag') -> None: + def add_auto_data_tag(self, addr: int, tag: 'Tag') -> None: """ ``add_auto_data_tag`` adds an already-created Tag object at a data address. If you want want to create the tag as well, consider using @@ -5084,7 +5173,7 @@ class BinaryView: """ core.BNAddAutoDataTag(self.handle, addr, tag.handle) - def create_auto_data_tag(self, addr:int, type:'TagType', data:str, unique:bool=False) -> 'Tag': + def create_auto_data_tag(self, addr: int, type: 'TagType', data: str, unique: bool = False) -> 'Tag': """ ``create_auto_data_tag`` creates and adds a Tag object at a data address. @@ -5105,7 +5194,7 @@ class BinaryView: core.BNAddAutoDataTag(self.handle, addr, tag.handle) return tag - def remove_auto_data_tag(self, addr:int, tag:'Tag') -> None: + def remove_auto_data_tag(self, addr: int, tag: 'Tag') -> None: """ ``remove_auto_data_tag`` removes a Tag object at a data address. Since this removes a user tag, it will be added to the current undo buffer. @@ -5116,7 +5205,7 @@ class BinaryView: """ core.BNRemoveAutoDataTag(self.handle, addr, tag.handle) - def remove_auto_data_tags_of_type(self, addr:int, tag_type:'TagType') -> None: + def remove_auto_data_tags_of_type(self, addr: int, tag_type: 'TagType') -> None: """ ``remove_auto_data_tags_of_type`` removes all data tags at the given address of the given type. Since this removes user tags, it will be added to the current undo buffer. @@ -5127,7 +5216,7 @@ class BinaryView: """ core.BNRemoveAutoDataTagsOfType(self.handle, addr, tag_type.handle) - def can_assemble(self, arch:Optional['architecture.Architecture']=None) -> bool: + def can_assemble(self, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``can_assemble`` queries the architecture plugin to determine if the architecture can assemble instructions. @@ -5145,7 +5234,7 @@ class BinaryView: arch = self.arch return core.BNCanAssemble(self.handle, arch.handle) - def is_never_branch_patch_available(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def is_never_branch_patch_available(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``is_never_branch_patch_available`` queries the architecture plugin to determine if the instruction at the instruction at ``addr`` can be made to **never branch**. The actual logic of which is implemented in the @@ -5173,7 +5262,7 @@ class BinaryView: arch = self.arch return core.BNIsNeverBranchPatchAvailable(self.handle, arch.handle, addr) - def is_always_branch_patch_available(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def is_always_branch_patch_available(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``is_always_branch_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` can be made to **always branch**. The actual logic of which is implemented in the @@ -5201,7 +5290,7 @@ class BinaryView: arch = self.arch return core.BNIsAlwaysBranchPatchAvailable(self.handle, arch.handle, addr) - def is_invert_branch_patch_available(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def is_invert_branch_patch_available(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``is_invert_branch_patch_available`` queries the architecture plugin to determine if the instruction at ``addr`` is a branch that can be inverted. The actual logic of which is implemented in the @@ -5230,7 +5319,9 @@ class BinaryView: arch = self.arch return core.BNIsInvertBranchPatchAvailable(self.handle, arch.handle, addr) - def is_skip_and_return_zero_patch_available(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def is_skip_and_return_zero_patch_available( + self, addr: int, arch: Optional['architecture.Architecture'] = None + ) -> 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 @@ -5259,7 +5350,9 @@ class BinaryView: arch = self.arch return core.BNIsSkipAndReturnZeroPatchAvailable(self.handle, arch.handle, addr) - def is_skip_and_return_value_patch_available(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def is_skip_and_return_value_patch_available( + self, addr: int, arch: Optional['architecture.Architecture'] = None + ) -> bool: """ ``is_skip_and_return_value_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 a value. The actual @@ -5288,7 +5381,7 @@ class BinaryView: arch = self.arch return core.BNIsSkipAndReturnValuePatchAvailable(self.handle, arch.handle, addr) - def convert_to_nop(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def convert_to_nop(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``convert_to_nop`` converts the instruction at virtual address ``addr`` to a nop of the provided architecture. @@ -5326,7 +5419,7 @@ class BinaryView: arch = self.arch return core.BNConvertToNop(self.handle, arch.handle, addr) - def always_branch(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def always_branch(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``always_branch`` convert the instruction of architecture ``arch`` at the virtual address ``addr`` to an unconditional branch. @@ -5354,7 +5447,7 @@ class BinaryView: arch = self.arch return core.BNAlwaysBranch(self.handle, arch.handle, addr) - def never_branch(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def never_branch(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``never_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to a fall through. @@ -5382,7 +5475,7 @@ class BinaryView: arch = self.arch return core.BNConvertToNop(self.handle, arch.handle, addr) - def invert_branch(self, addr:int, arch:Optional['architecture.Architecture']=None) -> bool: + def invert_branch(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``invert_branch`` convert the branch instruction of architecture ``arch`` at the virtual address ``addr`` to the inverse branch. @@ -5411,7 +5504,7 @@ class BinaryView: arch = self.arch return core.BNInvertBranch(self.handle, arch.handle, addr) - def skip_and_return_value(self, addr:int, value:int, arch:Optional['architecture.Architecture']=None) -> bool: + def skip_and_return_value(self, addr: int, value: int, arch: Optional['architecture.Architecture'] = None) -> bool: """ ``skip_and_return_value`` convert the ``call`` instruction of architecture ``arch`` at the virtual address ``addr`` to the equivalent of returning a value. @@ -5438,7 +5531,7 @@ class BinaryView: arch = self.arch return core.BNSkipAndReturnValue(self.handle, arch.handle, addr, value) - def get_instruction_length(self, addr:int, arch:Optional['architecture.Architecture']=None) -> int: + def get_instruction_length(self, addr: int, arch: Optional['architecture.Architecture'] = None) -> int: """ ``get_instruction_length`` returns the number of bytes in the instruction of Architecture ``arch`` at the virtual address ``addr`` @@ -5461,16 +5554,16 @@ class BinaryView: arch = self.arch return core.BNGetInstructionLength(self.handle, arch.handle, addr) - def notify_data_written(self, offset:int, length:int) -> None: + def notify_data_written(self, offset: int, length: int) -> None: core.BNNotifyDataWritten(self.handle, offset, length) - def notify_data_inserted(self, offset:int, length:int) -> None: + def notify_data_inserted(self, offset: int, length: int) -> None: core.BNNotifyDataInserted(self.handle, offset, length) - def notify_data_removed(self, offset:int, length:int) -> None: + def notify_data_removed(self, offset: int, length: int) -> None: core.BNNotifyDataRemoved(self.handle, offset, length) - def get_strings(self, start:Optional[int] = None, length:Optional[int] = None) -> List['StringReference']: + def get_strings(self, start: Optional[int] = None, length: Optional[int] = None) -> List['StringReference']: """ ``get_strings`` returns a list of strings defined in the binary in the optional virtual address range: ``start-(start+length)`` @@ -5504,7 +5597,7 @@ class BinaryView: finally: core.BNFreeStringReferenceList(strings) - def get_string_at(self, addr:int, partial:bool=False) -> Optional['StringReference']: + def get_string_at(self, addr: int, partial: bool = False) -> Optional['StringReference']: """ ``get_string_at`` returns the string that falls on given virtual address. @@ -5530,7 +5623,8 @@ class BinaryView: length = str_ref.length - (addr - str_ref.start) if partial else str_ref.length return StringReference(self, StringType(str_ref.type), start, length) - def get_ascii_string_at(self, addr:int, min_length:int=4, max_length:int=None, require_cstring:bool=True) -> Optional['StringReference']: + def get_ascii_string_at(self, addr: int, min_length: int = 4, max_length: int = None, + require_cstring: bool = True) -> Optional['StringReference']: """ ``get_ascii_string_at`` returns an ascii string found at ``addr``. @@ -5575,7 +5669,7 @@ class BinaryView: return None return StringReference(self, StringType.AsciiString, addr, length) - def add_analysis_completion_event(self, callback:Callable[[], None]) -> 'AnalysisCompletionEvent': + def add_analysis_completion_event(self, callback: Callable[[], None]) -> 'AnalysisCompletionEvent': """ ``add_analysis_completion_event`` sets up a call back function to be called when analysis has been completed. This is helpful when using :func:`update_analysis` which does not wait for analysis completion before returning. @@ -5600,7 +5694,7 @@ class BinaryView: """ return AnalysisCompletionEvent(self, callback) - def get_next_function_start_after(self, addr:int) -> int: + def get_next_function_start_after(self, addr: int) -> int: """ ``get_next_function_start_after`` returns the virtual address of the Function that occurs after the virtual address ``addr`` @@ -5622,7 +5716,7 @@ class BinaryView: """ return core.BNGetNextFunctionStartAfterAddress(self.handle, addr) - def get_next_basic_block_start_after(self, addr:int) -> int: + def get_next_basic_block_start_after(self, addr: int) -> int: """ ``get_next_basic_block_start_after`` returns the virtual address of the BasicBlock that occurs after the virtual address ``addr`` @@ -5640,7 +5734,7 @@ class BinaryView: """ return core.BNGetNextBasicBlockStartAfterAddress(self.handle, addr) - def get_next_data_after(self, addr:int) -> int: + def get_next_data_after(self, addr: int) -> int: """ ``get_next_data_after`` retrieves the virtual address of the next non-code byte. @@ -5654,7 +5748,7 @@ class BinaryView: """ return core.BNGetNextDataAfterAddress(self.handle, addr) - def get_next_data_var_after(self, addr:int) -> Optional['DataVariable']: + def get_next_data_var_after(self, addr: int) -> Optional['DataVariable']: """ ``get_next_data_var_after`` retrieves the next :py:Class:`DataVariable`, or None. @@ -5680,7 +5774,7 @@ class BinaryView: break return DataVariable.from_core_struct(var, self) - def get_next_data_var_start_after(self, addr:int) -> int: + def get_next_data_var_start_after(self, addr: int) -> int: """ ``get_next_data_var_start_after`` retrieves the next virtual address of the next :py:Class:`DataVariable` @@ -5697,7 +5791,7 @@ class BinaryView: """ return core.BNGetNextDataVariableStartAfterAddress(self.handle, addr) - def get_previous_function_start_before(self, addr:int) -> int: + def get_previous_function_start_before(self, addr: int) -> int: """ ``get_previous_function_start_before`` returns the virtual address of the Function that occurs prior to the virtual address provided @@ -5717,7 +5811,7 @@ class BinaryView: """ return core.BNGetPreviousFunctionStartBeforeAddress(self.handle, addr) - def get_previous_basic_block_start_before(self, addr:int) -> int: + def get_previous_basic_block_start_before(self, addr: int) -> int: """ ``get_previous_basic_block_start_before`` returns the virtual address of the BasicBlock that occurs prior to the provided virtual address @@ -5737,7 +5831,7 @@ class BinaryView: """ return core.BNGetPreviousBasicBlockStartBeforeAddress(self.handle, addr) - def get_previous_basic_block_end_before(self, addr:int) -> int: + def get_previous_basic_block_end_before(self, addr: int) -> int: """ ``get_previous_basic_block_end_before`` @@ -5754,7 +5848,7 @@ class BinaryView: """ return core.BNGetPreviousBasicBlockEndBeforeAddress(self.handle, addr) - def get_previous_data_before(self, addr:int) -> int: + def get_previous_data_before(self, addr: int) -> int: """ ``get_previous_data_before`` @@ -5769,7 +5863,7 @@ class BinaryView: """ return core.BNGetPreviousDataBeforeAddress(self.handle, addr) - def get_previous_data_var_before(self, addr:int) -> Optional['DataVariable']: + def get_previous_data_var_before(self, addr: int) -> Optional['DataVariable']: """ ``get_previous_data_var_before`` retrieves the previous :py:Class:`DataVariable`, or None. @@ -5790,7 +5884,7 @@ class BinaryView: return None return DataVariable.from_core_struct(var, self) - def get_previous_data_var_start_before(self, addr:int) -> int: + def get_previous_data_var_start_before(self, addr: int) -> int: """ ``get_previous_data_var_start_before`` @@ -5807,7 +5901,9 @@ class BinaryView: """ return core.BNGetPreviousDataVariableStartBeforeAddress(self.handle, addr) - def get_linear_disassembly_position_at(self, addr:int, settings:'_function.DisassemblySettings'=None) -> 'lineardisassembly.LinearViewCursor': + def get_linear_disassembly_position_at( + self, addr: int, settings: '_function.DisassemblySettings' = None + ) -> 'lineardisassembly.LinearViewCursor': """ ``get_linear_disassembly_position_at`` instantiates a :py:class:`LinearViewCursor ` object for use in :py:meth:`get_previous_linear_disassembly_lines` or :py:meth:`get_next_linear_disassembly_lines`. @@ -5829,7 +5925,9 @@ class BinaryView: pos.seek_to_address(addr) return pos - def get_previous_linear_disassembly_lines(self, pos:'lineardisassembly.LinearViewCursor') -> List['lineardisassembly.LinearDisassemblyLine']: + def get_previous_linear_disassembly_lines( + self, pos: 'lineardisassembly.LinearViewCursor' + ) -> List['lineardisassembly.LinearDisassemblyLine']: """ ``get_previous_linear_disassembly_lines`` retrieves a list of :py:class:`LinearDisassemblyLine` objects for the previous disassembly lines, and updates the LinearViewCursor passed in. This function can be called @@ -5853,7 +5951,9 @@ class BinaryView: result = pos.lines return result - def get_next_linear_disassembly_lines(self, pos:'lineardisassembly.LinearViewCursor') -> List['lineardisassembly.LinearDisassemblyLine']: + def get_next_linear_disassembly_lines( + self, pos: 'lineardisassembly.LinearViewCursor' + ) -> List['lineardisassembly.LinearDisassemblyLine']: """ ``get_next_linear_disassembly_lines`` retrieves a list of :py:class:`LinearDisassemblyLine` objects for the next disassembly lines, and updates the LinearViewCursor passed in. This function can be called @@ -5878,8 +5978,9 @@ class BinaryView: return result return result - def get_linear_disassembly(self, settings:'_function.DisassemblySettings'=None) -> \ - Iterator['lineardisassembly.LinearDisassemblyLine']: + def get_linear_disassembly( + self, settings: '_function.DisassemblySettings' = None + ) -> Iterator['lineardisassembly.LinearDisassemblyLine']: """ ``get_linear_disassembly`` gets an iterator for all lines in the linear disassembly of the view for the given disassembly settings. @@ -5902,12 +6003,13 @@ class BinaryView: """ @dataclass class LinearDisassemblyIterator: - view:'BinaryView' - settings:Optional['_function.DisassemblySettings'] = None + view: 'BinaryView' + settings: Optional['_function.DisassemblySettings'] = None def __iter__(self): - pos = lineardisassembly.LinearViewCursor(lineardisassembly.LinearViewObject.disassembly( - self.view, self.settings)) + pos = lineardisassembly.LinearViewCursor( + lineardisassembly.LinearViewObject.disassembly(self.view, self.settings) + ) while True: lines = self.view.get_next_linear_disassembly_lines(pos) if len(lines) == 0: @@ -5917,7 +6019,7 @@ class BinaryView: return iter(LinearDisassemblyIterator(self, settings)) - def parse_type_string(self, text:str) -> Tuple['_types.Type', '_types.QualifiedName']: + def parse_type_string(self, text: str) -> Tuple['_types.Type', '_types.QualifiedName']: """ ``parse_type_string`` parses string containing C into a single type :py:Class:`Type`. In contrast to the :py:'platform @@ -5944,13 +6046,13 @@ class BinaryView: error_str = errors.value.decode("utf-8") core.free_string(errors) raise SyntaxError(error_str) - type_obj = _types.Type.create(core.BNNewTypeReference(result.type), platform = self.platform) + type_obj = _types.Type.create(core.BNNewTypeReference(result.type), platform=self.platform) name = _types.QualifiedName._from_core_struct(result.name) return type_obj, name finally: core.BNFreeQualifiedNameAndType(result) - def parse_types_from_string(self, text:str) -> '_types.TypeParserResult': + def parse_types_from_string(self, text: str) -> '_types.TypeParserResult': """ ``parse_types_from_string`` parses string containing C into a :py:Class:`TypeParserResult` objects. This API unlike the :py:meth:`Platform.parse_types_from_source` allows the reference of types already defined @@ -5980,23 +6082,31 @@ class BinaryView: core.free_string(errors) raise SyntaxError(error_str) - type_dict:Mapping[_types.QualifiedName, _types.Type] = {} - variables:Mapping[_types.QualifiedName, _types.Type] = {} - functions:Mapping[_types.QualifiedName, _types.Type] = {} + type_dict: Mapping[_types.QualifiedName, _types.Type] = {} + variables: Mapping[_types.QualifiedName, _types.Type] = {} + functions: Mapping[_types.QualifiedName, _types.Type] = {} for i in range(0, parse.typeCount): name = _types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = _types.Type.create(core.BNNewTypeReference(parse.types[i].type), platform = self.platform) + type_dict[name] = _types.Type.create( + core.BNNewTypeReference(parse.types[i].type), platform=self.platform + ) for i in range(0, parse.variableCount): name = _types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = _types.Type.create(core.BNNewTypeReference(parse.variables[i].type), platform = self.platform) + variables[name] = _types.Type.create( + core.BNNewTypeReference(parse.variables[i].type), platform=self.platform + ) for i in range(0, parse.functionCount): name = _types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = _types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform = self.platform) + functions[name] = _types.Type.create( + core.BNNewTypeReference(parse.functions[i].type), platform=self.platform + ) return _types.TypeParserResult(type_dict, variables, functions) finally: core.BNFreeTypeParserResult(parse) - def parse_possiblevalueset(self, value:str, state:RegisterValueType, here:int=0) -> 'variable.PossibleValueSet': + def parse_possiblevalueset( + self, value: str, state: RegisterValueType, here: int = 0 + ) -> 'variable.PossibleValueSet': """ Evaluates a string representation of a PossibleValueSet into an instance of the ``PossibleValueSet`` value. @@ -6043,7 +6153,7 @@ class BinaryView: raise ValueError(error_str) return variable.PossibleValueSet(self.arch, result) - def get_type_by_name(self, name:'_types.QualifiedNameType') -> Optional['_types.Type']: + def get_type_by_name(self, name: '_types.QualifiedNameType') -> Optional['_types.Type']: """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` @@ -6062,9 +6172,9 @@ class BinaryView: obj = core.BNGetAnalysisTypeByName(self.handle, _name) if not obj: return None - return _types.Type.create(obj, platform = self.platform) + return _types.Type.create(obj, platform=self.platform) - def get_type_by_id(self, id:str) -> Optional['_types.Type']: + def get_type_by_id(self, id: str) -> Optional['_types.Type']: """ ``get_type_by_id`` returns the defined type whose unique identifier corresponds with the provided ``id`` @@ -6083,9 +6193,9 @@ class BinaryView: obj = core.BNGetAnalysisTypeById(self.handle, id) if not obj: return None - return _types.Type.create(obj, platform = self.platform) + return _types.Type.create(obj, platform=self.platform) - def get_type_name_by_id(self, id:str) -> Optional['_types.QualifiedName']: + def get_type_name_by_id(self, id: str) -> Optional['_types.QualifiedName']: """ ``get_type_name_by_id`` returns the defined type name whose unique identifier corresponds with the provided ``id`` @@ -6109,7 +6219,7 @@ class BinaryView: return None return result - def get_type_id(self, name:'_types.QualifiedNameType') -> str: + def get_type_id(self, name: '_types.QualifiedNameType') -> str: """ ``get_type_id`` returns the unique identifier of the defined type whose name corresponds with the provided ``name`` @@ -6129,7 +6239,7 @@ class BinaryView: _name = _types.QualifiedName(name)._to_core_struct() return core.BNGetAnalysisTypeId(self.handle, _name) - def add_type_library(self, lib:'typelibrary.TypeLibrary') -> None: + def add_type_library(self, lib: 'typelibrary.TypeLibrary') -> None: """ ``add_type_library`` make the contents of a type library available for type/import resolution @@ -6140,7 +6250,7 @@ class BinaryView: raise ValueError("must pass in a TypeLibrary object") core.BNAddBinaryViewTypeLibrary(self.handle, lib.handle) - def get_type_library(self, name:str) -> Optional['typelibrary.TypeLibrary']: + def get_type_library(self, name: str) -> Optional['typelibrary.TypeLibrary']: """ ``get_type_library`` returns the TypeLibrary @@ -6155,7 +6265,7 @@ class BinaryView: return None return typelibrary.TypeLibrary(handle) - def is_type_auto_defined(self, name:'_types.QualifiedNameType') -> bool: + def is_type_auto_defined(self, name: '_types.QualifiedNameType') -> bool: """ ``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name is considered an *auto* type. @@ -6173,7 +6283,9 @@ class BinaryView: _name = _types.QualifiedName(name)._to_core_struct() return core.BNIsAnalysisTypeAutoDefined(self.handle, _name) - def define_type(self, type_id:str, default_name:Optional['_types.QualifiedNameType'], type_obj:StringOrType) -> '_types.QualifiedName': + def define_type( + self, type_id: str, default_name: Optional['_types.QualifiedNameType'], type_obj: StringOrType + ) -> '_types.QualifiedName': """ ``define_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of types for the current :py:Class:`BinaryView`. This method should only be used for automatically generated types. @@ -6205,7 +6317,7 @@ class BinaryView: core.BNFreeQualifiedName(reg_name) return result - def define_user_type(self, name:Optional['_types.QualifiedNameType'], type_obj:StringOrType) -> None: + def define_user_type(self, name: Optional['_types.QualifiedNameType'], type_obj: StringOrType) -> None: """ ``define_user_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of user types for the current :py:Class:`BinaryView`. @@ -6232,7 +6344,7 @@ class BinaryView: _name = _types.QualifiedName(name)._to_core_struct() core.BNDefineUserAnalysisType(self.handle, _name, type_obj.handle) - def undefine_type(self, type_id:str) -> None: + def undefine_type(self, type_id: str) -> None: """ ``undefine_type`` removes a :py:Class:`Type` from the global list of types for the current :py:Class:`BinaryView` @@ -6251,7 +6363,7 @@ class BinaryView: """ core.BNUndefineAnalysisType(self.handle, type_id) - def undefine_user_type(self, name:'_types.QualifiedNameType') -> None: + def undefine_user_type(self, name: '_types.QualifiedNameType') -> None: """ ``undefine_user_type`` removes a :py:Class:`Type` from the global list of user types for the current :py:Class:`BinaryView` @@ -6271,7 +6383,7 @@ class BinaryView: _name = _types.QualifiedName(name)._to_core_struct() core.BNUndefineUserAnalysisType(self.handle, _name) - def rename_type(self, old_name:'_types.QualifiedNameType', new_name:'_types.QualifiedNameType') -> None: + def rename_type(self, old_name: '_types.QualifiedNameType', new_name: '_types.QualifiedNameType') -> None: """ ``rename_type`` renames a type in the global list of types for the current :py:Class:`BinaryView` @@ -6293,7 +6405,7 @@ class BinaryView: _new_name = _types.QualifiedName(new_name)._to_core_struct() core.BNRenameAnalysisType(self.handle, _old_name, _new_name) - def import_library_type(self, name:str, lib:typelibrary.TypeLibrary = None) -> Optional['_types.Type']: + def import_library_type(self, name: str, lib: typelibrary.TypeLibrary = None) -> Optional['_types.Type']: """ ``import_library_type`` recursively imports a type from the specified type library, or, if no library was explicitly provided, the first type library associated with the current :py:Class:`BinaryView` @@ -6312,12 +6424,14 @@ class BinaryView: :rtype: Type """ _name = _types.QualifiedName(name) - handle = core.BNBinaryViewImportTypeLibraryType(self.handle, None if lib is None else lib.handle, _name._to_core_struct()) + handle = core.BNBinaryViewImportTypeLibraryType( + self.handle, None if lib is None else lib.handle, _name._to_core_struct() + ) if handle is None: return None - return _types.Type.create(handle, platform = self.platform) + return _types.Type.create(handle, platform=self.platform) - def import_library_object(self, name:str, lib:typelibrary.TypeLibrary = None) -> Optional['_types.Type']: + def import_library_object(self, name: str, lib: typelibrary.TypeLibrary = None) -> Optional['_types.Type']: """ ``import_library_object`` recursively imports an object from the specified type library, or, if no library was explicitly provided, the first type library associated with the current :py:Class:`BinaryView` @@ -6332,12 +6446,14 @@ class BinaryView: :rtype: Type """ _name = _types.QualifiedName(name) - handle = core.BNBinaryViewImportTypeLibraryObject(self.handle, None if lib is None else lib.handle, _name._to_core_struct()) + handle = core.BNBinaryViewImportTypeLibraryObject( + self.handle, None if lib is None else lib.handle, _name._to_core_struct() + ) if handle is None: return None - return _types.Type.create(handle, platform = self.platform) + return _types.Type.create(handle, platform=self.platform) - def export_type_to_library(self, lib:typelibrary.TypeLibrary, name:Optional[str], type_obj:StringOrType) -> None: + def export_type_to_library(self, lib: typelibrary.TypeLibrary, name: Optional[str], type_obj: StringOrType) -> None: """ ``export_type_to_library`` recursively exports ``type_obj`` into ``lib`` as a type with name ``name`` @@ -6364,7 +6480,9 @@ class BinaryView: raise ValueError("name can only be None if named type is derived from string passed to type_obj") core.BNBinaryViewExportTypeToTypeLibrary(self.handle, lib.handle, _name._to_core_struct(), type_obj.handle) - def export_object_to_library(self, lib:typelibrary.TypeLibrary, name:Optional[str], type_obj:StringOrType) -> None: + def export_object_to_library( + self, lib: typelibrary.TypeLibrary, name: Optional[str], type_obj: StringOrType + ) -> None: """ ``export_object_to_library`` recursively exports ``type_obj`` into ``lib`` as an object with name ``name`` @@ -6392,7 +6510,7 @@ class BinaryView: raise ValueError("name can only be None if named type is derived from string passed to type_obj") core.BNBinaryViewExportObjectToTypeLibrary(self.handle, lib.handle, _name._to_core_struct(), type_obj.handle) - def register_platform_types(self, platform:'_platform.Platform') -> None: + def register_platform_types(self, platform: '_platform.Platform') -> None: """ ``register_platform_types`` ensures that the platform-specific types for a :py:Class:`Platform` are available for the current :py:Class:`BinaryView`. This is automatically performed when adding a new function or setting @@ -6408,7 +6526,7 @@ class BinaryView: """ core.BNRegisterPlatformTypes(self.handle, platform.handle) - def find_next_data(self, start:int, data:bytes, flags:FindFlag=FindFlag.FindCaseSensitive) -> Optional[int]: + def find_next_data(self, start: int, data: bytes, flags: FindFlag = FindFlag.FindCaseSensitive) -> Optional[int]: """ ``find_next_data`` searches for the bytes ``data`` starting at the virtual address ``start`` until the end of the BinaryView. @@ -6432,10 +6550,11 @@ class BinaryView: return None return result.value - - def find_next_text(self, start:int, text:str, settings:_function.DisassemblySettings=None, - flags:FindFlag=FindFlag.FindCaseSensitive, - graph_type:FunctionGraphType = FunctionGraphType.NormalFunctionGraph) -> Optional[int]: + def find_next_text( + self, start: int, text: str, settings: _function.DisassemblySettings = None, + flags: FindFlag = FindFlag.FindCaseSensitive, + graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph + ) -> Optional[int]: """ ``find_next_text`` searches for string ``text`` occurring in the linear view output starting at the virtual address ``start`` until the end of the BinaryView. @@ -6461,13 +6580,14 @@ class BinaryView: raise TypeError("settings parameter is not DisassemblySettings type") result = ctypes.c_ulonglong() - if not core.BNFindNextText(self.handle, start, text, result, settings.handle, flags, - graph_type): + if not core.BNFindNextText(self.handle, start, text, result, settings.handle, flags, graph_type): return None return result.value - def find_next_constant(self, start:int, constant:int, settings:_function.DisassemblySettings=None, - graph_type:FunctionGraphType = FunctionGraphType.NormalFunctionGraph) -> Optional[int]: + def find_next_constant( + self, start: int, constant: int, settings: _function.DisassemblySettings = None, + graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph + ) -> Optional[int]: """ ``find_next_constant`` searches for integer constant ``constant`` occurring in the linear view output starting at the virtual address ``start`` until the end of the BinaryView. @@ -6485,8 +6605,7 @@ class BinaryView: raise TypeError("settings parameter is not DisassemblySettings type") result = ctypes.c_ulonglong() - if not core.BNFindNextConstant(self.handle, start, constant, result, settings.handle, - graph_type): + if not core.BNFindNextConstant(self.handle, start, constant, result, settings.handle, graph_type): return None return result.value @@ -6507,8 +6626,10 @@ class BinaryView: if (not self.thread.is_alive()) and self.results.empty(): raise StopIteration - def find_all_data(self, start:int, end:int, data:bytes, flags:FindFlag = FindFlag.FindCaseSensitive, - progress_func:ProgressFuncType = None, match_callback:DataMatchCallbackType = None) -> QueueGenerator: + def find_all_data( + self, start: int, end: int, data: bytes, flags: FindFlag = FindFlag.FindCaseSensitive, + progress_func: ProgressFuncType = None, match_callback: DataMatchCallbackType = None + ) -> QueueGenerator: """ ``find_all_data`` searches for the bytes ``data`` starting at the virtual address ``start`` until the virtual address ``end``. Once a match is found, the ``match_callback`` is called. @@ -6542,35 +6663,40 @@ class BinaryView: raise TypeError('flag parameter must have type FindFlag') if progress_func: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: progress_func(cur, total)) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: progress_func(cur, total)) else: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: True) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: True) if match_callback: # the `not match_callback(...) is False` tolerates the users who forget to return # `True` from inside the callback - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer))\ - (lambda ctxt, addr, match: not match_callback(addr, databuffer.DataBuffer(handle = match)) is False) - return core.BNFindAllDataWithProgress(self.handle, start, end, buf.handle, flags, - None, progress_func_obj, None, match_callback_obj) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer) + )(lambda ctxt, addr, match: not match_callback(addr, databuffer.DataBuffer(handle=match)) is False) + return core.BNFindAllDataWithProgress( + self.handle, start, end, buf.handle, flags, None, progress_func_obj, None, match_callback_obj + ) else: results = queue.Queue() - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer))\ - (lambda ctxt, addr, match: - results.put((addr, databuffer.DataBuffer(handle = match))) or True) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer) + )(lambda ctxt, addr, match: results.put((addr, databuffer.DataBuffer(handle=match))) or True) - t = threading.Thread(target = lambda: core.BNFindAllDataWithProgress(self.handle, - start, end, buf.handle, flags, None, progress_func_obj, None, match_callback_obj)) + t = threading.Thread( + target=lambda: core.BNFindAllDataWithProgress( + self.handle, start, end, buf.handle, flags, None, progress_func_obj, None, match_callback_obj + ) + ) return self.QueueGenerator(t, results) - def _LinearDisassemblyLine_convertor(self, lines:core.BNLinearDisassemblyLineHandle) -> 'lineardisassembly.LinearDisassemblyLine': + def _LinearDisassemblyLine_convertor( + self, lines: core.BNLinearDisassemblyLineHandle + ) -> 'lineardisassembly.LinearDisassemblyLine': func = None block = None line = lines[0] @@ -6583,13 +6709,14 @@ class BinaryView: color = highlight.HighlightColor._from_core_struct(line.contents.highlight) addr = line.contents.addr tokens = _function.InstructionTextToken._from_core_struct(line.contents.tokens, line.contents.count) - contents = _function.DisassemblyTextLine(tokens, addr, color = color) + contents = _function.DisassemblyTextLine(tokens, addr, color=color) return lineardisassembly.LinearDisassemblyLine(line.type, func, block, contents) - def find_all_text(self, start:int, end:int, text:str, settings:_function.DisassemblySettings = None, - flags = FindFlag.FindCaseSensitive, - graph_type = FunctionGraphType.NormalFunctionGraph, progress_func = None, - match_callback = None) -> QueueGenerator: + def find_all_text( + self, start: int, end: int, text: str, settings: _function.DisassemblySettings = None, + flags=FindFlag.FindCaseSensitive, graph_type=FunctionGraphType.NormalFunctionGraph, progress_func=None, + match_callback=None + ) -> QueueGenerator: """ ``find_all_text`` searches for string ``text`` occurring in the linear view output starting at the virtual address ``start`` until the virtual address ``end``. Once a match is found, @@ -6631,43 +6758,54 @@ class BinaryView: raise TypeError('flag parameter must have type FindFlag') if progress_func: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: progress_func(cur, total)) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: progress_func(cur, total)) else: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: True) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: True) if match_callback: # The reason we use `not match_callback(...) is False` is the user tends to happily # deal with the returned data, but forget to return True at the end of the callback. # Then only the first result will be returned. - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_char_p, - ctypes.POINTER(core.BNLinearDisassemblyLine))\ - (lambda ctxt, addr, match, line: not match_callback(addr, match,\ - self._LinearDisassemblyLine_convertor(line)) is False) - - return core.BNFindAllTextWithProgress(self.handle, start, end, text, - settings.handle, flags, graph_type, None, progress_func_obj, None, match_callback_obj) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_char_p, + ctypes.POINTER(core.BNLinearDisassemblyLine) + )( + lambda ctxt, addr, match, line: + not match_callback(addr, match, self._LinearDisassemblyLine_convertor(line)) is False + ) + + return core.BNFindAllTextWithProgress( + self.handle, start, end, text, settings.handle, flags, graph_type, None, progress_func_obj, None, + match_callback_obj + ) else: results = queue.Queue() - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_char_p, - ctypes.POINTER(core.BNLinearDisassemblyLine))\ - (lambda ctxt, addr, match, line: results.put((addr, match,\ - self._LinearDisassemblyLine_convertor(line))) or True) - - t = threading.Thread(target = lambda: core.BNFindAllTextWithProgress(self.handle, - start, end, text, settings.handle, flags, graph_type, None, progress_func_obj, None, - match_callback_obj)) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_char_p, + ctypes.POINTER(core.BNLinearDisassemblyLine) + )( + lambda ctxt, addr, match, line: results.put((addr, match, self._LinearDisassemblyLine_convertor(line))) + or True + ) + + t = threading.Thread( + target=lambda: core.BNFindAllTextWithProgress( + self.handle, start, end, text, settings.handle, flags, graph_type, None, progress_func_obj, None, + match_callback_obj + ) + ) return self.QueueGenerator(t, results) - def find_all_constant(self, start:int, end:int, constant:int, settings:_function.DisassemblySettings = None, - graph_type:FunctionGraphType = FunctionGraphType.NormalFunctionGraph, progress_func:ProgressFuncType = None, - match_callback:LineMatchCallbackType = None) -> QueueGenerator: + def find_all_constant( + self, start: int, end: int, constant: int, settings: _function.DisassemblySettings = None, + graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph, progress_func: ProgressFuncType = None, + match_callback: LineMatchCallbackType = None + ) -> QueueGenerator: """ ``find_all_constant`` searches for the integer constant ``constant`` starting at the virtual address ``start`` until the virtual address ``end``. Once a match is found, @@ -6698,32 +6836,35 @@ class BinaryView: raise TypeError("settings parameter is not DisassemblySettings type") if progress_func: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: progress_func(cur, total)) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: progress_func(cur, total)) else: - progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, - ctypes.c_ulonglong, ctypes.c_ulonglong)\ - (lambda ctxt, cur, total: True) + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: True) if match_callback: - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p,\ - ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine))\ - (lambda ctxt, addr, line: not match_callback(addr,\ - self._LinearDisassemblyLine_convertor(line)) is False) - - return core.BNFindAllConstantWithProgress(self.handle, start, end, constant, - settings.handle, graph_type, None, progress_func_obj, None, match_callback_obj) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine) + )(lambda ctxt, addr, line: not match_callback(addr, self._LinearDisassemblyLine_convertor(line)) is False) + + return core.BNFindAllConstantWithProgress( + self.handle, start, end, constant, settings.handle, graph_type, None, progress_func_obj, None, + match_callback_obj + ) else: results = queue.Queue() - match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p,\ - ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine))\ - (lambda ctxt, addr, line: results.put((addr,\ - self._LinearDisassemblyLine_convertor(line))) or True) + match_callback_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine) + )(lambda ctxt, addr, line: results.put((addr, self._LinearDisassemblyLine_convertor(line))) or True) - t = threading.Thread(target = lambda: core.BNFindAllConstantWithProgress(self.handle, - start, end, constant, settings.handle, graph_type, None, progress_func_obj, None,\ - match_callback_obj)) + t = threading.Thread( + target=lambda: core.BNFindAllConstantWithProgress( + self.handle, start, end, constant, settings.handle, graph_type, None, progress_func_obj, None, + match_callback_obj + ) + ) return self.QueueGenerator(t, results) @@ -6740,9 +6881,10 @@ class BinaryView: handle = core.BNGetWorkflowForBinaryView(self.handle) if handle is None: return None - return _workflow.Workflow(handle = handle) + return _workflow.Workflow(handle=handle) - def rebase(self, address:int, force:bool = False, progress_func:ProgressFuncType = None) -> Optional['BinaryView']: + def rebase(self, address: int, force: bool = False, + progress_func: ProgressFuncType = None) -> Optional['BinaryView']: """ ``rebase`` rebase the existing :py:class:`BinaryView` into a new :py:class:`BinaryView` at the specified virtual address @@ -6757,22 +6899,27 @@ class BinaryView: """ result = False if core.BNIsUIEnabled() and not force: - log_warn("The BinaryView rebase API does not update cooresponding UI components. If the BinaryView is not associated with the UI rerun with 'force = True'.") + log_warn( + "The BinaryView rebase API does not update cooresponding UI components. If the BinaryView is not associated with the UI rerun with 'force = True'." + ) return None if progress_func is None: result = core.BNRebase(self.handle, address) else: - result = core.BNRebaseWithProgress(self.handle, address, None, ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( - lambda ctxt, cur, total: progress_func(cur, total))) + result = core.BNRebaseWithProgress( + self.handle, address, None, + ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, + ctypes.c_ulonglong)(lambda ctxt, cur, total: progress_func(cur, total)) + ) if result: return self.get_view_of_type(self.view_type) else: return None - def show_plain_text_report(self, title:str, contents:str) -> None: + def show_plain_text_report(self, title: str, contents: str) -> None: core.BNShowPlainTextReport(self.handle, title, contents) - def show_markdown_report(self, title:str, contents:str, plaintext:str = "") -> None: + def show_markdown_report(self, title: str, contents: str, plaintext: str = "") -> None: """ ``show_markdown_report`` displays the markdown contents in UI applications and plaintext in command-line applications. Markdown reports support hyperlinking into the BinaryView. Hyperlinks can be specified as follows: @@ -6790,7 +6937,7 @@ class BinaryView: """ core.BNShowMarkdownReport(self.handle, title, contents, plaintext) - def show_html_report(self, title:str, contents:str, plaintext:str = "") -> None: + def show_html_report(self, title: str, contents: str, plaintext: str = "") -> None: """ ``show_html_report`` displays the HTML contents in UI applications and plaintext in command-line applications. HTML reports support hyperlinking into the BinaryView. Hyperlinks can be specified as follows: @@ -6808,7 +6955,7 @@ class BinaryView: """ core.BNShowHTMLReport(self.handle, title, contents, plaintext) - def show_graph_report(self, title:str, graph:flowgraph.FlowGraph) -> None: + def show_graph_report(self, title: str, graph: flowgraph.FlowGraph) -> None: """ ``show_graph_report`` displays a :py:Class:`FlowGraph` object `graph` in a new tab with ``title``. @@ -6819,7 +6966,7 @@ class BinaryView: """ core.BNShowGraphReport(self.handle, title, graph.handle) - def get_address_input(self, prompt:str, title:str, current_address:int = None) -> Optional[int]: + def get_address_input(self, prompt: str, title: str, current_address: int = None) -> Optional[int]: if current_address is None: current_address = self._file.offset value = ctypes.c_ulonglong() @@ -6827,10 +6974,10 @@ class BinaryView: return None return value.value - def add_auto_segment(self, start:int, length:int, data_offset:int, data_length:int, flags:SegmentFlag) -> None: + def add_auto_segment(self, start: int, length: int, data_offset: int, data_length: int, flags: SegmentFlag) -> None: core.BNAddAutoSegment(self.handle, start, length, data_offset, data_length, flags) - def remove_auto_segment(self, start:int, length:int) -> None: + def remove_auto_segment(self, start: int, length: int) -> None: """ ``remove_auto_segment`` removes an automatically generated segment from the current segment mapping. @@ -6843,7 +6990,7 @@ class BinaryView: """ core.BNRemoveAutoSegment(self.handle, start, length) - def add_user_segment(self, start:int, length:int, data_offset:int, data_length:int, flags:SegmentFlag) -> None: + def add_user_segment(self, start: int, length: int, data_offset: int, data_length: int, flags: SegmentFlag) -> None: """ ``add_user_segment`` creates a user-defined segment that specifies how data from the raw file is mapped into a virtual address space. @@ -6856,10 +7003,10 @@ class BinaryView: """ core.BNAddUserSegment(self.handle, start, length, data_offset, data_length, flags) - def remove_user_segment(self, start:int, length:int) -> None: + def remove_user_segment(self, start: int, length: int) -> None: core.BNRemoveUserSegment(self.handle, start, length) - def get_segment_at(self, addr:int) -> Optional[Segment]: + def get_segment_at(self, addr: int) -> Optional[Segment]: seg = core.BNGetSegmentAt(self.handle, addr) if not seg: return None @@ -6867,7 +7014,7 @@ class BinaryView: assert segment_handle is not None, "core.BNNewSegmentReference returned None" return Segment(segment_handle) - def get_address_for_data_offset(self, offset:int) -> Optional[int]: + def get_address_for_data_offset(self, offset: int) -> Optional[int]: """ ``get_address_for_data_offset`` returns the virtual address that maps to the specific file offset. @@ -6880,7 +7027,7 @@ class BinaryView: return None return address.value - def get_data_offset_for_address(self, address:int) -> Optional[int]: + def get_data_offset_for_address(self, address: int) -> Optional[int]: """ ``get_data_offset_for_address`` returns the file offset that maps to the given virtual address, if possible. @@ -6897,17 +7044,24 @@ class BinaryView: return offset + segment.data_offset return None - def add_auto_section(self, name:str, start:int, length:int, - semantics:SectionSemantics = SectionSemantics.DefaultSectionSemantics, type:str = "", - align:int = 1, entry_size:int = 1, linked_section:str = "", info_section:str = "", info_data:int = 0) -> None: - core.BNAddAutoSection(self.handle, name, start, length, semantics, type, align, entry_size, linked_section, - info_section, info_data) - - def remove_auto_section(self, name:str) -> None: + def add_auto_section( + self, name: str, start: int, length: int, + semantics: SectionSemantics = SectionSemantics.DefaultSectionSemantics, type: str = "", align: int = 1, + entry_size: int = 1, linked_section: str = "", info_section: str = "", info_data: int = 0 + ) -> None: + core.BNAddAutoSection( + self.handle, name, start, length, semantics, type, align, entry_size, linked_section, info_section, + info_data + ) + + def remove_auto_section(self, name: str) -> None: core.BNRemoveAutoSection(self.handle, name) - def add_user_section(self, name:str, start:int, length:int, semantics:SectionSemantics = SectionSemantics.DefaultSectionSemantics, - type:str = "", align:int = 1, entry_size:int = 1, linked_section:str = "", info_section:str = "", info_data:int = 0) -> None: + def add_user_section( + self, name: str, start: int, length: int, + semantics: SectionSemantics = SectionSemantics.DefaultSectionSemantics, type: str = "", align: int = 1, + entry_size: int = 1, linked_section: str = "", info_section: str = "", info_data: int = 0 + ) -> None: """ ``add_user_section`` creates a user-defined section that can help inform analysis by clarifying what types of data exist in what ranges. Note that all data specified must already be mapped by an existing segment. @@ -6924,13 +7078,15 @@ class BinaryView: :param int info_data: optional info data :rtype: None """ - core.BNAddUserSection(self.handle, name, start, length, semantics, type, align, entry_size, linked_section, - info_section, info_data) + core.BNAddUserSection( + self.handle, name, start, length, semantics, type, align, entry_size, linked_section, info_section, + info_data + ) - def remove_user_section(self, name:str) -> None: + def remove_user_section(self, name: str) -> None: core.BNRemoveUserSection(self.handle, name) - def get_sections_at(self, addr:int) -> List[Section]: + def get_sections_at(self, addr: int) -> List[Section]: count = ctypes.c_ulonglong(0) section_list = core.BNGetSectionsAt(self.handle, addr, count) assert section_list is not None, "core.BNGetSectionsAt returned None" @@ -6944,7 +7100,7 @@ class BinaryView: finally: core.BNFreeSectionList(section_list, count.value) - def get_section_by_name(self, name:str) -> Optional[Section]: + def get_section_by_name(self, name: str) -> Optional[Section]: section = core.BNGetSectionByName(self.handle, name) if section is None: return None @@ -6953,7 +7109,7 @@ class BinaryView: result = Section(section_handle) return result - def get_unique_section_names(self, name_list:List[str]) -> List[str]: + def get_unique_section_names(self, name_list: List[str]) -> List[str]: incoming_names = (ctypes.c_char_p * len(name_list))() for i in range(0, len(name_list)): incoming_names[i] = name_list[i].encode("utf-8") @@ -6990,7 +7146,7 @@ class BinaryView: finally: core.BNFreeAddressList(addrs) - def get_comment_at(self, addr:int) -> str: + def get_comment_at(self, addr: int) -> str: """ ``get_comment_at`` returns the address-based comment attached to the given address in this BinaryView Note that address-based comments are different from function-level comments which are specific to each _function. @@ -7001,7 +7157,7 @@ class BinaryView: """ return core.BNGetGlobalCommentForAddress(self.handle, addr) - def set_comment_at(self, addr:int, comment:str) -> None: + def set_comment_at(self, addr: int, comment: str) -> None: """ ``set_comment_at`` sets a comment for the BinaryView at the address specified @@ -7039,7 +7195,7 @@ class BinaryView: raise ValueError("Attempting to apply_debug_info with something which isn't and instance of 'DebugInfo'") core.BNApplyDebugInfo(self.handle, value.handle) - def query_metadata(self, key:str) -> 'metadata.MetadataValueType': + def query_metadata(self, key: str) -> 'metadata.MetadataValueType': """ `query_metadata` retrieves a metadata associated with the given key stored in the current BinaryView. @@ -7062,7 +7218,7 @@ class BinaryView: raise KeyError(key) return metadata.Metadata(handle=md_handle).value - def store_metadata(self, key:str, md:metadata.MetadataValueType, isAuto:bool = False) -> None: + def store_metadata(self, key: str, md: metadata.MetadataValueType, isAuto: bool = False) -> None: """ `store_metadata` stores an object for the given key in the current BinaryView. Objects stored using `store_metadata` can be retrieved when the database is reopened. Objects stored are not arbitrary python @@ -7094,7 +7250,7 @@ class BinaryView: _md = metadata.Metadata(_md) core.BNBinaryViewStoreMetadata(self.handle, key, _md.handle, isAuto) - def remove_metadata(self, key:str) -> None: + def remove_metadata(self, key: str) -> None: """ `remove_metadata` removes the metadata associated with key from the current BinaryView. @@ -7126,7 +7282,7 @@ class BinaryView: finally: core.BNFreeStringList(names, count.value) - def get_load_settings(self, type_name:str) -> Optional[settings.Settings]: + def get_load_settings(self, type_name: str) -> Optional[settings.Settings]: """ ``get_load_settings`` retrieve a :py:class:`Settings` object which defines the load settings for the given :py:class:`BinaryViewType` ``type_name`` @@ -7139,7 +7295,7 @@ class BinaryView: return None return settings.Settings(handle=settings_handle) - def set_load_settings(self, type_name:str, settings:settings.Settings) -> None: + def set_load_settings(self, type_name: str, settings: settings.Settings) -> None: """ ``set_load_settings`` set a :py:class:`settings.Settings` object which defines the load settings for the given :py:class:`BinaryViewType` ``type_name`` @@ -7151,7 +7307,7 @@ class BinaryView: settings = settings.handle core.BNBinaryViewSetLoadSettings(self.handle, type_name, settings) - def parse_expression(self, expression:str, here:int=0) -> int: + def parse_expression(self, expression: str, here: int = 0) -> int: r""" Evaluates a string expression to an integer value. @@ -7194,22 +7350,22 @@ class BinaryView: raise ValueError(error_str) return offset.value - def eval(self, expression:str, here:int=0) -> int: + def eval(self, expression: str, here: int = 0) -> int: """ Evaluates an string expression to an integer value. This is a more concise alias for the :py:meth:`parse_expression` API """ return self.parse_expression(expression, here) - def reader(self, address:Optional[int]=None) -> 'BinaryReader': + def reader(self, address: Optional[int] = None) -> 'BinaryReader': return BinaryReader(self, address=address) - def writer(self, address:Optional[int]=None) -> 'BinaryWriter': + def writer(self, address: Optional[int] = None) -> 'BinaryWriter': return BinaryWriter(self, address=address) @property def libraries(self) -> List[str]: try: - result:List[str] = [] + result: List[str] = [] libs = self.query_metadata("Libraries") assert isinstance(libs, metadata.Metadata) for s in libs: @@ -7219,7 +7375,7 @@ class BinaryView: except KeyError: return [] - def typed_data_accessor(self, address:int, type:'_types.Type') -> 'TypedDataAccessor': + def typed_data_accessor(self, address: int, type: '_types.Type') -> 'TypedDataAccessor': return TypedDataAccessor(type, address, self, self.endianness) @@ -7244,7 +7400,7 @@ class BinaryReader: '0xcffaedfeL' >>> """ - def __init__(self, view:'BinaryView', endian:Optional[Endianness]=None, address:Optional[int]=None): + def __init__(self, view: 'BinaryView', endian: Optional[Endianness] = None, address: Optional[int] = None): _handle = core.BNCreateBinaryReader(view.handle) assert _handle is not None, "core.BNCreateBinaryReader returned None" self._handle = _handle @@ -7285,7 +7441,7 @@ class BinaryReader: return Endianness(core.BNGetBinaryReaderEndianness(self._handle)) @endianness.setter - def endianness(self, value:Endianness) -> None: + def endianness(self, value: Endianness) -> None: core.BNSetBinaryReaderEndianness(self._handle, value) @property @@ -7300,7 +7456,7 @@ class BinaryReader: return core.BNGetReaderPosition(self._handle) @offset.setter - def offset(self, value:int) -> None: + def offset(self, value: int) -> None: core.BNSeekBinaryReader(self._handle, value) @property @@ -7313,7 +7469,7 @@ class BinaryReader: """ return core.BNIsEndOfFile(self._handle) - def read(self, length:int, address:Optional[int]=None) -> Optional[bytes]: + def read(self, length: int, address: Optional[int] = None) -> Optional[bytes]: """ ``read`` returns ``length`` bytes read from the current offset, adding ``length`` to offset. @@ -7335,7 +7491,7 @@ class BinaryReader: return None return dest.raw - def read8(self, address:Optional[int]=None) -> Optional[int]: + def read8(self, address: Optional[int] = None) -> Optional[int]: """ ``read8`` returns a one byte integer from offset incrementing the offset. @@ -7357,7 +7513,7 @@ class BinaryReader: return None return result.value - def read16(self, address:Optional[int]=None) -> Optional[int]: + def read16(self, address: Optional[int] = None) -> Optional[int]: """ ``read16`` returns a two byte integer from offset incrementing the offset by two, using specified endianness. @@ -7379,7 +7535,7 @@ class BinaryReader: return None return result.value - def read32(self, address:Optional[int]=None) -> Optional[int]: + def read32(self, address: Optional[int] = None) -> Optional[int]: """ ``read32`` returns a four byte integer from offset incrementing the offset by four, using specified endianness. @@ -7401,7 +7557,7 @@ class BinaryReader: return None return result.value - def read64(self, address:Optional[int]=None) -> Optional[int]: + def read64(self, address: Optional[int] = None) -> Optional[int]: """ ``read64`` returns an eight byte integer from offset incrementing the offset by eight, using specified endianness. @@ -7423,7 +7579,7 @@ class BinaryReader: return None return result.value - def read16le(self, address:Optional[int]=None) -> Optional[int]: + def read16le(self, address: Optional[int] = None) -> Optional[int]: """ ``read16le`` returns a two byte little endian integer from offset incrementing the offset by two. @@ -7445,7 +7601,7 @@ class BinaryReader: return None return struct.unpack(" Optional[int]: + def read32le(self, address: Optional[int] = None) -> Optional[int]: """ ``read32le`` returns a four byte little endian integer from offset incrementing the offset by four. @@ -7467,7 +7623,7 @@ class BinaryReader: return None return struct.unpack(" Optional[int]: + def read64le(self, address: Optional[int] = None) -> Optional[int]: """ ``read64le`` returns an eight byte little endian integer from offset incrementing the offset by eight. @@ -7489,7 +7645,7 @@ class BinaryReader: return None return struct.unpack(" Optional[int]: + def read16be(self, address: Optional[int] = None) -> Optional[int]: """ ``read16be`` returns a two byte big endian integer from offset incrementing the offset by two. @@ -7511,7 +7667,7 @@ class BinaryReader: return None return struct.unpack(">H", result)[0] - def read32be(self, address:Optional[int]=None) -> Optional[int]: + def read32be(self, address: Optional[int] = None) -> Optional[int]: """ ``read32be`` returns a four byte big endian integer from offset incrementing the offset by four. @@ -7532,7 +7688,7 @@ class BinaryReader: return None return struct.unpack(">I", result)[0] - def read64be(self, address:Optional[int]=None) -> Optional[int]: + def read64be(self, address: Optional[int] = None) -> Optional[int]: """ ``read64be`` returns an eight byte big endian integer from offset incrementing the offset by eight. @@ -7553,7 +7709,7 @@ class BinaryReader: return None return struct.unpack(">Q", result)[0] - def seek(self, offset:int) -> None: + def seek(self, offset: int) -> None: """ ``seek`` update internal offset to ``offset``. @@ -7570,7 +7726,7 @@ class BinaryReader: """ core.BNSeekBinaryReader(self._handle, offset) - def seek_relative(self, offset:int) -> None: + def seek_relative(self, offset: int) -> None: """ ``seek_relative`` updates the internal offset by ``offset``. @@ -7610,7 +7766,7 @@ class BinaryWriter: >>> bw = BinaryWriter(bv, Endianness.BigEndian) >>> """ - def __init__(self, view:BinaryView, endian:Optional[Endianness] = None, address:Optional[int]=None): + def __init__(self, view: BinaryView, endian: Optional[Endianness] = None, address: Optional[int] = None): self._handle = core.BNCreateBinaryWriter(view.handle) assert self._handle is not None, "core.BNCreateBinaryWriter returned None" self._view = view @@ -7654,7 +7810,7 @@ class BinaryWriter: return core.BNGetBinaryWriterEndianness(self._handle) @endianness.setter - def endianness(self, value:Endianness) -> None: + def endianness(self, value: Endianness) -> None: core.BNSetBinaryWriterEndianness(self._handle, value) @property @@ -7669,10 +7825,10 @@ class BinaryWriter: return core.BNGetWriterPosition(self._handle) @offset.setter - def offset(self, value:int) -> None: + def offset(self, value: int) -> None: core.BNSeekBinaryWriter(self._handle, value) - def write(self, value:bytes, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write(self, value: bytes, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write`` writes ``len(value)`` bytes to the internal offset, without regard to endianness. @@ -7700,7 +7856,7 @@ class BinaryWriter: ctypes.memmove(buf, value, len(value)) return core.BNWriteData(self._handle, buf, len(value)) - def write8(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write8(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write8`` lowest order byte from the integer ``value`` to the current offset. @@ -7724,7 +7880,7 @@ class BinaryWriter: raise RelocationWriteException("Attempting to write to a location which has a relocation") return core.BNWrite8(self._handle, value) - def write16(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write16(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write16`` writes the lowest order two bytes from the integer ``value`` to the current offset, using internal endianness. @@ -7741,7 +7897,7 @@ class BinaryWriter: raise RelocationWriteException("Attempting to write to a location which has a relocation") return core.BNWrite16(self._handle, value) - def write32(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write32(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write32`` writes the lowest order four bytes from the integer ``value`` to the current offset, using internal endianness. @@ -7758,7 +7914,7 @@ class BinaryWriter: raise RelocationWriteException("Attempting to write to a location which has a relocation") return core.BNWrite32(self._handle, value) - def write64(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write64(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write64`` writes the lowest order eight bytes from the integer ``value`` to the current offset, using internal endianness. @@ -7775,7 +7931,7 @@ class BinaryWriter: raise RelocationWriteException("Attempting to write to a location which has a relocation") return core.BNWrite64(self._handle, value) - def write16le(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write16le(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write16le`` writes the lowest order two bytes from the little endian integer ``value`` to the current offset. @@ -7789,7 +7945,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(" bool: + def write32le(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write32le`` writes the lowest order four bytes from the little endian integer ``value`` to the current offset. @@ -7803,7 +7959,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(" bool: + def write64le(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write64le`` writes the lowest order eight bytes from the little endian integer ``value`` to the current offset. @@ -7817,7 +7973,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(" bool: + def write16be(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write16be`` writes the lowest order two bytes from the big endian integer ``value`` to the current offset. @@ -7831,7 +7987,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(">H", value), except_on_relocation=except_on_relocation) - def write32be(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write32be(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write32be`` writes the lowest order four bytes from the big endian integer ``value`` to the current offset. @@ -7845,7 +8001,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(">I", value), except_on_relocation=except_on_relocation) - def write64be(self, value:int, address:Optional[int]=None, except_on_relocation=True) -> bool: + def write64be(self, value: int, address: Optional[int] = None, except_on_relocation=True) -> bool: """ ``write64be`` writes the lowest order eight bytes from the big endian integer ``value`` to the current offset. @@ -7859,7 +8015,7 @@ class BinaryWriter: self.seek(address) return self.write(struct.pack(">Q", value), except_on_relocation=except_on_relocation) - def seek(self, offset:int) -> None: + def seek(self, offset: int) -> None: """ ``seek`` update internal offset to ``offset``. @@ -7876,7 +8032,7 @@ class BinaryWriter: """ core.BNSeekBinaryWriter(self._handle, offset) - def seek_relative(self, offset:int) -> None: + def seek_relative(self, offset: int) -> None: """ ``seek_relative`` updates the internal offset by ``offset``. @@ -7899,10 +8055,10 @@ class StructuredDataValue(object): """ DEPRECATED use: TypedDataAccessor instead. """ - type:'_types.Type' - address:int - value:bytes - endian:Endianness + type: '_types.Type' + address: int + value: bytes + endian: Endianness def __str__(self): decode_str = "{}B".format(self.type.width) @@ -7956,7 +8112,7 @@ class StructuredDataView(object): 003e >>> """ - def __init__(self, bv:'BinaryView', structure_name:'_types.QualifiedNameType', address:int): + def __init__(self, bv: 'BinaryView', structure_name: '_types.QualifiedNameType', address: int): self._bv = bv self._structure_name = structure_name self._address = address @@ -7988,7 +8144,7 @@ class StructuredDataView(object): return self[key] - def __getitem__(self, key:str) -> Optional[StructuredDataValue]: + def __getitem__(self, key: str) -> Optional[StructuredDataValue]: m = self._members.get(key, None) if m is None: return None @@ -8027,10 +8183,10 @@ class StructuredDataView(object): @dataclass class TypedDataAccessor: - type:'_types.Type' - address:int - view:'BinaryView' - endian:Endianness + type: '_types.Type' + address: int + view: 'BinaryView' + endian: Endianness def __post_init__(self): if not isinstance(self.type, _types.Type): @@ -8060,7 +8216,7 @@ class TypedDataAccessor: return self.int_from_bytes(bytes(self), len(self), bool(_type.signed), self.endian) raise Exception(f"Attempting to coerce non integral type: {type(_type)} to an integer") - def __getitem__(self, key:Union[str, int]) -> 'TypedDataAccessor': + def __getitem__(self, key: Union[str, int]) -> 'TypedDataAccessor': _type = self.type if isinstance(_type, _types.NamedTypeReferenceType): _type = _type.target(self.view) @@ -8078,12 +8234,14 @@ class TypedDataAccessor: return TypedDataAccessor(m.type.immutable_copy(), self.address + m.offset, self.view, self.endian) @staticmethod - def byte_order(endian) -> str: # as of python3.8 -> Literal["little", "big"] + def byte_order(endian) -> str: # as of python3.8 -> Literal["little", "big"] return "little" if endian == Endianness.LittleEndian else "big" @staticmethod - def int_from_bytes(data:bytes, width:int, sign:bool, endian:Optional[Endianness]=None) -> int: - return int.from_bytes(data[0:width], byteorder=TypedDataAccessor.byte_order(endian), signed=sign) # type: ignore + def int_from_bytes(data: bytes, width: int, sign: bool, endian: Optional[Endianness] = None) -> int: + return int.from_bytes( + data[0:width], byteorder=TypedDataAccessor.byte_order(endian), signed=sign + ) # type: ignore def __float__(self): if not isinstance(self.type, _types.FloatType): @@ -8104,14 +8262,13 @@ class TypedDataAccessor: return self._value_helper(self.type, self.view.read(self.address, len(self.type))) @value.setter - def value(self, data:Union[bytes, int]) -> None: + def value(self, data: Union[bytes, int]) -> None: if isinstance(data, int): - integral_types = (_types.IntegerType, _types.IntegerBuilder, - _types.BoolType, _types.BoolBuilder, - _types.CharType, _types.CharBuilder, - _types.WideCharType, _types.WideCharBuilder, - _types.PointerType, _types.PointerBuilder, - _types.EnumerationType, _types.EnumerationBuilder) + integral_types = ( + _types.IntegerType, _types.IntegerBuilder, _types.BoolType, _types.BoolBuilder, _types.CharType, + _types.CharBuilder, _types.WideCharType, _types.WideCharBuilder, _types.PointerType, + _types.PointerBuilder, _types.EnumerationType, _types.EnumerationBuilder + ) if not isinstance(self.type, integral_types): raise TypeError(f"Can't set the value of type {type(self.type)} to int value") to_write = data.to_bytes(len(self), TypedDataAccessor.byte_order(self.endian)) # type: ignore @@ -8131,7 +8288,7 @@ class TypedDataAccessor: count = self.view.write(self.address, to_write) assert count == len(to_write), "Unable to write all bytes to the location, segment might not have file backing" - def _value_helper(self, _type:'_types.Type', data:bytes) -> Any: + def _value_helper(self, _type: '_types.Type', data: bytes) -> Any: if not isinstance(_type, _types.Type): raise TypeError(f"Attempting to get value of TypeBuilder of type {type(_type)}") if isinstance(_type, _types.NamedTypeReferenceType): @@ -8140,7 +8297,7 @@ class TypedDataAccessor: raise ValueError("Couldn't find target for type") _type = target - if isinstance(_type, (_types.VoidType, _types.FunctionType)): #, _types.VarArgsType, _types.ValueType)): + if isinstance(_type, (_types.VoidType, _types.FunctionType)): #, _types.VarArgsType, _types.ValueType)): return None elif isinstance(_type, _types.BoolType): return bool(self) @@ -8153,7 +8310,8 @@ class TypedDataAccessor: elif isinstance(_type, _types.StructureType): result = {} for member in _type.members: - result[member.name] = TypedDataAccessor(member.type, self.address + member.offset, self.view, self.endian).value + result[member.name + ] = TypedDataAccessor(member.type, self.address + member.offset, self.view, self.endian).value return result elif isinstance(_type, _types.EnumerationType): value = int(self) @@ -8168,7 +8326,9 @@ class TypedDataAccessor: if _type.element_type.width == 1 and _type.element_type.type_class == TypeClass.IntegerTypeClass: return bytes(self) for offset in range(0, len(_type), _type.element_type.width): - result.append(TypedDataAccessor(_type.element_type, self.address + offset, self.view, self.endian).value) + result.append( + TypedDataAccessor(_type.element_type, self.address + offset, self.view, self.endian).value + ) return result else: raise TypeError(f"Unhandled `Type` {type(_type)}") @@ -8177,11 +8337,12 @@ class TypedDataAccessor: # for backward compatibility TypedDataReader = TypedDataAccessor + @dataclass class CoreDataVariable: - _address:int - _type:'_types.Type' - _auto_discovered:bool + _address: int + _type: '_types.Type' + _auto_discovered: bool def __len__(self): return len(self._type) @@ -8200,15 +8361,16 @@ class CoreDataVariable: class DataVariable(CoreDataVariable): - def __init__(self, view:BinaryView, address:int, type:'_types.Type', auto_discovered:bool): + def __init__(self, view: BinaryView, address: int, type: '_types.Type', auto_discovered: bool): super(DataVariable, self).__init__(address, type, auto_discovered) self.view = view self._sdv = TypedDataAccessor(self.type, self.address, self.view, self.view.endianness) @classmethod - def from_core_struct(cls, var:core.BNDataVariable, view:'BinaryView') -> 'DataVariable': - var_type = _types.Type.create(core.BNNewTypeReference(var.type), platform=view.platform, - confidence=var.typeConfidence) + def from_core_struct(cls, var: core.BNDataVariable, view: 'BinaryView') -> 'DataVariable': + var_type = _types.Type.create( + core.BNNewTypeReference(var.type), platform=view.platform, confidence=var.typeConfidence + ) return cls(view, var.address, var_type, var.autoDiscovered) @property @@ -8237,10 +8399,10 @@ class DataVariable(CoreDataVariable): return self._sdv.value @value.setter - def value(self, data:bytes) -> None: + def value(self, data: bytes) -> None: self._sdv.value = data - def __getitem__(self, item:str): + def __getitem__(self, item: str): return self._sdv[item] @property @@ -8248,7 +8410,7 @@ class DataVariable(CoreDataVariable): return self._type @type.setter - def type(self, value:Optional['_types.Type']) -> None: # type: ignore + def type(self, value: Optional['_types.Type']) -> None: # type: ignore _type = value if value is not None else _types.VoidType.create() assert self.view.define_user_data_var(self.address, _type) is not None, "Unable to set DataVariable's type" self._type = _type @@ -8258,7 +8420,7 @@ class DataVariable(CoreDataVariable): return self.view.get_symbol_at(self.address) @symbol.setter - def symbol(self, value:Optional[Union[str, '_types.CoreSymbol']]) -> None: # type: ignore + def symbol(self, value: Optional[Union[str, '_types.CoreSymbol']]) -> None: # type: ignore if value is None or value == "": if self.symbol is not None: self.view.undefine_user_symbol(self.symbol) @@ -8277,14 +8439,14 @@ class DataVariable(CoreDataVariable): return self.symbol.name @name.setter - def name(self, value:str) -> None: + def name(self, value: str) -> None: self.symbol = value class DataVariableAndName(CoreDataVariable): - def __init__(self, addr:int, var_type:'_types.Type', var_name:str, auto_discovered:bool) -> None: + def __init__(self, addr: int, var_type: '_types.Type', var_name: str, auto_discovered: bool) -> None: super(DataVariableAndName, self).__init__(addr, var_type, auto_discovered) self.name = var_name def __repr__(self) -> str: - return f"" \ No newline at end of file + return f"" diff --git a/python/bncompleter.py b/python/bncompleter.py index ba012a2a..ff093b9d 100644 --- a/python/bncompleter.py +++ b/python/bncompleter.py @@ -48,6 +48,7 @@ from typing import Optional __all__ = ["Completer"] + def fnsignature(obj): if sys.version_info[0:2] >= (3, 5): try: @@ -59,14 +60,14 @@ def fnsignature(obj): try: args = inspect.getargspec(obj).args args.remove('self') - sig = "(" + ','.join(args) + ")" + sig = "(" + ','.join(args) + ")" except: sig = "()" return sig class Completer: - def __init__(self, namespace = None): + def __init__(self, namespace=None): """Create a new completer for the command line. Completer([namespace]) -> completer instance. @@ -93,7 +94,7 @@ class Completer: self.use_main_ns = 0 self.namespace = namespace - def complete(self, text:str, state) -> Optional[str]: + def complete(self, text: str, state) -> Optional[str]: """Return the next possible completion for 'text'. This is called successively with state == 0, 1, 2, ... until it @@ -140,16 +141,14 @@ class Completer: seen.add(word) if word in {'finally', 'try'}: word = word + ':' - elif word not in {'False', 'None', 'True', - 'break', 'continue', 'pass', - 'else'}: + elif word not in {'False', 'None', 'True', 'break', 'continue', 'pass', 'else'}: word = word + ' ' matches.append(word) #Not sure why in the console builtins becomes a dict but this works for now. if hasattr(__builtins__, '__dict__'): # type: ignore # remove this ignore > pyright 1.1.149 - builtins = __builtins__.__dict__ # type: ignore # remove this ignore > pyright 1.1.149 + builtins = __builtins__.__dict__ # type: ignore # remove this ignore > pyright 1.1.149 else: - builtins = __builtins__ # type: ignore # remove this ignore > pyright 1.1.149 + builtins = __builtins__ # type: ignore # remove this ignore > pyright 1.1.149 for nspace in [self.namespace, builtins]: for word, val in nspace.items(): if word[:n] == text and word not in seen: @@ -196,7 +195,7 @@ class Completer: noprefix = None while True: for word in words: - if (word[:n] == attr and not (noprefix and word[:n+1] == noprefix)): + if (word[:n] == attr and not (noprefix and word[:n + 1] == noprefix)): match = f"{expr}.{word}" try: val = inspect.getattr_static(thisobject, word) @@ -214,9 +213,10 @@ class Completer: matches.sort() return matches + def get_class_members(klass): ret = dir(klass) - if hasattr(klass,'__bases__'): + if hasattr(klass, '__bases__'): for base in klass.__bases__: ret = ret + get_class_members(base) return ret diff --git a/python/callingconvention.py b/python/callingconvention.py index 89040119..44d835b7 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -29,8 +29,7 @@ from . import variable from . import function from . import architecture -FunctionOrILFunction = Union["binaryninja.function.Function", - "binaryninja.lowlevelil.LowLevelILFunction", +FunctionOrILFunction = Union["binaryninja.function.Function", "binaryninja.lowlevelil.LowLevelILFunction", "binaryninja.mediumlevelil.MediumLevelILFunction", "binaryninja.highlevelil.HighLevelILFunction"] @@ -54,7 +53,10 @@ class CallingConvention: _registered_calling_conventions = [] - def __init__(self, arch:'architecture.Architecture'=None, name:str=None, handle=None, confidence:int=core.max_confidence): + def __init__( + self, arch: 'architecture.Architecture' = None, name: str = None, handle=None, + confidence: int = core.max_confidence + ): if handle is None: if arch is None or name is None: raise ValueError("Must specify either handle or architecture and name") @@ -64,23 +66,49 @@ class CallingConvention: self._cb.context = 0 self._cb.getCallerSavedRegisters = self._cb.getCallerSavedRegisters.__class__(self._get_caller_saved_regs) self._cb.getCalleeSavedRegisters = self._cb.getCalleeSavedRegisters.__class__(self._get_callee_saved_regs) - self._cb.getIntegerArgumentRegisters = self._cb.getIntegerArgumentRegisters.__class__(self._get_int_arg_regs) + self._cb.getIntegerArgumentRegisters = self._cb.getIntegerArgumentRegisters.__class__( + self._get_int_arg_regs + ) self._cb.getFloatArgumentRegisters = self._cb.getFloatArgumentRegisters.__class__(self._get_float_arg_regs) self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) - self._cb.areArgumentRegistersSharedIndex = self._cb.areArgumentRegistersSharedIndex.__class__(self._arg_regs_share_index) - self._cb.areArgumentRegistersUsedForVarArgs = self._cb.areArgumentRegistersUsedForVarArgs.__class__(self._arg_regs_used_for_varargs) - self._cb.isStackReservedForArgumentRegisters = self._cb.isStackReservedForArgumentRegisters.__class__(self._stack_reserved_for_arg_regs) - self._cb.isStackAdjustedOnReturn = self._cb.isStackAdjustedOnReturn.__class__(self._stack_adjusted_on_return) + self._cb.areArgumentRegistersSharedIndex = self._cb.areArgumentRegistersSharedIndex.__class__( + self._arg_regs_share_index + ) + self._cb.areArgumentRegistersUsedForVarArgs = self._cb.areArgumentRegistersUsedForVarArgs.__class__( + self._arg_regs_used_for_varargs + ) + self._cb.isStackReservedForArgumentRegisters = self._cb.isStackReservedForArgumentRegisters.__class__( + self._stack_reserved_for_arg_regs + ) + self._cb.isStackAdjustedOnReturn = self._cb.isStackAdjustedOnReturn.__class__( + self._stack_adjusted_on_return + ) self._cb.isEligibleForHeuristics = self._cb.isEligibleForHeuristics.__class__(self._eligible_for_heuristics) - self._cb.getIntegerReturnValueRegister = self._cb.getIntegerReturnValueRegister.__class__(self._get_int_return_reg) - self._cb.getHighIntegerReturnValueRegister = self._cb.getHighIntegerReturnValueRegister.__class__(self._get_high_int_return_reg) - self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__(self._get_float_return_reg) - self._cb.getGlobalPointerRegister = self._cb.getGlobalPointerRegister.__class__(self._get_global_pointer_reg) - self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__(self._get_implicitly_defined_regs) - self._cb.getIncomingRegisterValue = self._cb.getIncomingRegisterValue.__class__(self._get_incoming_reg_value) + self._cb.getIntegerReturnValueRegister = self._cb.getIntegerReturnValueRegister.__class__( + self._get_int_return_reg + ) + self._cb.getHighIntegerReturnValueRegister = self._cb.getHighIntegerReturnValueRegister.__class__( + self._get_high_int_return_reg + ) + self._cb.getFloatReturnValueRegister = self._cb.getFloatReturnValueRegister.__class__( + self._get_float_return_reg + ) + self._cb.getGlobalPointerRegister = self._cb.getGlobalPointerRegister.__class__( + self._get_global_pointer_reg + ) + self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__( + self._get_implicitly_defined_regs + ) + self._cb.getIncomingRegisterValue = self._cb.getIncomingRegisterValue.__class__( + self._get_incoming_reg_value + ) self._cb.getIncomingFlagValue = self._cb.getIncomingFlagValue.__class__(self._get_incoming_flag_value) - self._cb.getIncomingVariableForParameterVariable = self._cb.getIncomingVariableForParameterVariable.__class__(self._get_incoming_var_for_parameter_var) - self._cb.getParameterVariableForIncomingVariable = self._cb.getParameterVariableForIncomingVariable.__class__(self._get_parameter_var_for_incoming_var) + self._cb.getIncomingVariableForParameterVariable = self._cb.getIncomingVariableForParameterVariable.__class__( + self._get_incoming_var_for_parameter_var + ) + self._cb.getParameterVariableForIncomingVariable = self._cb.getParameterVariableForIncomingVariable.__class__( + self._get_parameter_var_for_incoming_var + ) _handle = core.BNCreateCallingConvention(arch.handle, name, self._cb) self.__class__._registered_calling_conventions.append(self) else: @@ -352,7 +380,7 @@ class CallingConvention: def _get_incoming_reg_value(self, ctxt, reg, func, result): try: - func_obj = function.Function(handle = core.BNNewFunctionReference(func)) + func_obj = function.Function(handle=core.BNNewFunctionReference(func)) reg_name = self.arch.get_reg_name(reg) api_obj = self.perform_get_incoming_reg_value(reg_name, func_obj)._to_core_struct() except: @@ -363,7 +391,7 @@ class CallingConvention: def _get_incoming_flag_value(self, ctxt, reg, func, result): try: - func_obj = function.Function(handle = core.BNNewFunctionReference(func)) + func_obj = function.Function(handle=core.BNNewFunctionReference(func)) reg_name = self.arch.get_reg_name(reg) api_obj = self.perform_get_incoming_flag_value(reg_name, func_obj)._to_core_struct() except: @@ -377,7 +405,7 @@ class CallingConvention: if func is None: func_obj = None else: - func_obj = function.Function(handle = core.BNNewFunctionReference(func)) + func_obj = function.Function(handle=core.BNNewFunctionReference(func)) 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 @@ -394,7 +422,7 @@ class CallingConvention: if func is None: func_obj = None else: - func_obj = function.Function(handle = core.BNNewFunctionReference(func)) + func_obj = function.Function(handle=core.BNNewFunctionReference(func)) 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 @@ -406,45 +434,62 @@ class CallingConvention: result[0].index = in_var[0].index result[0].storage = in_var[0].storage - def perform_get_incoming_reg_value(self, reg:'architecture.RegisterName', func:'function.Function') -> 'variable.RegisterValue': + def perform_get_incoming_reg_value( + self, reg: 'architecture.RegisterName', func: 'function.Function' + ) -> 'variable.RegisterValue': reg_stack = self.arch.get_reg_stack_for_reg(reg) if reg_stack is not None: if reg == self.arch.reg_stacks[reg_stack].stack_top_reg: return variable.ConstantRegisterValue(0) return variable.Undetermined() - def perform_get_incoming_flag_value(self, reg:'architecture.RegisterName', func:'function.Function') -> 'variable.RegisterValue': + def perform_get_incoming_flag_value( + self, reg: 'architecture.RegisterName', func: 'function.Function' + ) -> 'variable.RegisterValue': return variable.Undetermined() - def perform_get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', - func:Optional['function.Function']=None) -> 'variable.CoreVariable': + def perform_get_incoming_var_for_parameter_var( + self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None + ) -> 'variable.CoreVariable': 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:'variable.CoreVariable', - func:Optional['function.Function']=None) -> 'variable.CoreVariable': + def perform_get_parameter_var_for_incoming_var( + self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None + ) -> 'variable.CoreVariable': out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_var.to_BNVariable()) return variable.CoreVariable.from_BNVariable(out_var) - def with_confidence(self, confidence:int) -> 'CallingConvention': - return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle), - confidence = confidence) + def with_confidence(self, confidence: int) -> 'CallingConvention': + return CallingConvention( + self.arch, handle=core.BNNewCallingConventionReference(self.handle), confidence=confidence + ) - def get_incoming_reg_value(self, reg:'architecture.RegisterType', func:'function.Function') -> 'variable.RegisterValue': + def get_incoming_reg_value( + self, reg: 'architecture.RegisterType', func: 'function.Function' + ) -> 'variable.RegisterValue': reg_num = self.arch.get_reg_index(reg) func_handle = None if func is not None: func_handle = func.handle - return variable.RegisterValue.from_BNRegisterValue(core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle), self.arch) + return variable.RegisterValue.from_BNRegisterValue( + core.BNGetIncomingRegisterValue(self.handle, reg_num, func_handle), self.arch + ) - def get_incoming_flag_value(self, flag:'architecture.FlagIndex', func:'function.Function') -> 'variable.RegisterValue': + def get_incoming_flag_value( + self, flag: 'architecture.FlagIndex', func: 'function.Function' + ) -> 'variable.RegisterValue': reg_num = self.arch.get_flag_index(flag) func_handle = None if func is not None: func_handle = func.handle - return variable.RegisterValue.from_BNRegisterValue(core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle), self.arch) + return variable.RegisterValue.from_BNRegisterValue( + core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle), self.arch + ) - def get_incoming_var_for_parameter_var(self, in_var:'variable.CoreVariable', func:FunctionOrILFunction) -> 'variable.Variable': + def get_incoming_var_for_parameter_var( + self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction + ) -> 'variable.Variable': in_buf = in_var.to_BNVariable() if func is None: func_obj = None @@ -453,7 +498,9 @@ class CallingConvention: out_var = core.BNGetIncomingVariableForParameterVariable(self.handle, in_buf, func_obj) return variable.Variable.from_BNVariable(func, out_var) - def get_parameter_var_for_incoming_var(self, in_var:'variable.CoreVariable', func:FunctionOrILFunction) -> 'variable.Variable': + def get_parameter_var_for_incoming_var( + self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction + ) -> 'variable.Variable': in_buf = in_var.to_BNVariable() if func is None: func_obj = None @@ -467,5 +514,5 @@ class CallingConvention: return self._arch @arch.setter - def arch(self, value:'architecture.Architecture') -> None: + def arch(self, value: 'architecture.Architecture') -> None: self._arch = value diff --git a/python/commonil.py b/python/commonil.py index 9e9f6fea..7517574d 100644 --- a/python/commonil.py +++ b/python/commonil.py @@ -24,11 +24,12 @@ from .enums import BranchType from .interaction import show_graph_report from .log import log_warn + # This file contains a list of top level abstract classes for implementing BNIL instructions @dataclass(frozen=True, repr=False, eq=False) class BaseILInstruction: @classmethod - def prepend_parent(cls, graph:FlowGraph, node:FlowGraphNode, nodes={}): + def prepend_parent(cls, graph: FlowGraph, node: FlowGraphNode, nodes={}): for parent in cls.__bases__: if not issubclass(parent, BaseILInstruction): continue @@ -54,6 +55,7 @@ class BaseILInstruction: def show_hierarchy_graph(cls): show_graph_report(f"{cls.__name__}", cls.add_subgraph(FlowGraph(), {})) + @dataclass(frozen=True, repr=False, eq=False) class Constant(BaseILInstruction): pass @@ -123,6 +125,7 @@ class Localcall(Call): class Tailcall(Localcall): pass + @dataclass(frozen=True, repr=False, eq=False) class Return(Terminal): pass diff --git a/python/compatibility.py b/python/compatibility.py index bae8a6d3..fef7e49b 100644 --- a/python/compatibility.py +++ b/python/compatibility.py @@ -20,6 +20,7 @@ import sys + def pyNativeStr(arg): if isinstance(arg, str): return arg @@ -36,5 +37,3 @@ def valid_import(mod_name): mod_loader = importlib.find_loader(mod_name) found = mod_loader is not None return found - - diff --git a/python/database.py b/python/database.py index a563d99c..b9b81058 100644 --- a/python/database.py +++ b/python/database.py @@ -28,322 +28,322 @@ from . import filemetadata class KeyValueStore: - """ + """ ``class KeyValueStore`` maintains access to the raw data stored in Snapshots and various other Database-related structures. """ - def __init__(self, buffer: Optional[databuffer.DataBuffer] = None, handle=None): - if handle is not None: - self.handle = core.handle_of_type(handle, core.BNKeyValueStore) - else: - if buffer is None: - _handle = core.BNCreateKeyValueStore() - else: - _handle = core.BNCreateKeyValueStoreFromDataBuffer(buffer.handle) - assert _handle is not None - self.handle = _handle - - def __del__(self): - core.BNFreeKeyValueStore(self.handle) - - def __getitem__(self, item: str) -> databuffer.DataBuffer: - return self.get_value(item) - - def __setitem__(self, key: str, value: databuffer.DataBuffer): - return self.set_value(key, value) - - @property - def keys(self): - """Get a list of all keys stored in the kvs (read-only)""" - count = ctypes.c_ulonglong(0) - value = core.BNGetKeyValueStoreKeys(self.handle, count) - assert value is not None - - result = [] - try: - for i in range(0, count.value): - result.append(value[i]) - return result - finally: - core.BNFreeStringList(value, count) - - def get_value(self, key: str) -> databuffer.DataBuffer: - """Get the value for a single key""" - handle = core.BNGetKeyValueStoreBuffer(self.handle, key) - assert handle is not None - return databuffer.DataBuffer(handle=handle) - - def set_value(self, key: str, value: databuffer.DataBuffer): - """Set the value for a single key""" - core.BNSetKeyValueStoreBuffer(self.handle, key, value.handle) - - @property - def serialized_data(self) -> databuffer.DataBuffer: - """Get the stored representation of the kvs (read-only)""" - handle = core.BNGetKeyValueStoreSerializedData(self.handle) - assert handle is not None - return databuffer.DataBuffer(handle=handle) - - def begin_namespace(self, name: str): - """Begin storing new keys into a namespace""" - core.BNBeginKeyValueStoreNamespace(self.handle, name) - - def end_namespace(self): - """End storing new keys into a namespace""" - core.BNEndKeyValueStoreNamespace(self.handle) - - @property - def empty(self) -> bool: - """If the kvs is empty (read-only)""" - return core.BNIsKeyValueStoreEmpty(self.handle) - - @property - def value_size(self) -> bool: - """Number of values in the kvs (read-only)""" - return core.BNGetKeyValueStoreValueSize(self.handle) - - @property - def data_size(self) -> bool: - """Length of serialized data (read-only)""" - return core.BNGetKeyValueStoreDataSize(self.handle) - - @property - def value_storage_size(self) -> bool: - """Size of all data in storage (read-only)""" - return core.BNGetKeyValueStoreValueStorageSize(self.handle) - - @property - def namespace_size(self) -> bool: - """Number of namespaces pushed with begin_namespace (read-only)""" - return core.BNGetKeyValueStoreNamespaceSize(self.handle) + def __init__(self, buffer: Optional[databuffer.DataBuffer] = None, handle=None): + if handle is not None: + self.handle = core.handle_of_type(handle, core.BNKeyValueStore) + else: + if buffer is None: + _handle = core.BNCreateKeyValueStore() + else: + _handle = core.BNCreateKeyValueStoreFromDataBuffer(buffer.handle) + assert _handle is not None + self.handle = _handle + + def __del__(self): + core.BNFreeKeyValueStore(self.handle) + + def __getitem__(self, item: str) -> databuffer.DataBuffer: + return self.get_value(item) + + def __setitem__(self, key: str, value: databuffer.DataBuffer): + return self.set_value(key, value) + + @property + def keys(self): + """Get a list of all keys stored in the kvs (read-only)""" + count = ctypes.c_ulonglong(0) + value = core.BNGetKeyValueStoreKeys(self.handle, count) + assert value is not None + + result = [] + try: + for i in range(0, count.value): + result.append(value[i]) + return result + finally: + core.BNFreeStringList(value, count) + + def get_value(self, key: str) -> databuffer.DataBuffer: + """Get the value for a single key""" + handle = core.BNGetKeyValueStoreBuffer(self.handle, key) + assert handle is not None + return databuffer.DataBuffer(handle=handle) + + def set_value(self, key: str, value: databuffer.DataBuffer): + """Set the value for a single key""" + core.BNSetKeyValueStoreBuffer(self.handle, key, value.handle) + + @property + def serialized_data(self) -> databuffer.DataBuffer: + """Get the stored representation of the kvs (read-only)""" + handle = core.BNGetKeyValueStoreSerializedData(self.handle) + assert handle is not None + return databuffer.DataBuffer(handle=handle) + + def begin_namespace(self, name: str): + """Begin storing new keys into a namespace""" + core.BNBeginKeyValueStoreNamespace(self.handle, name) + + def end_namespace(self): + """End storing new keys into a namespace""" + core.BNEndKeyValueStoreNamespace(self.handle) + + @property + def empty(self) -> bool: + """If the kvs is empty (read-only)""" + return core.BNIsKeyValueStoreEmpty(self.handle) + + @property + def value_size(self) -> bool: + """Number of values in the kvs (read-only)""" + return core.BNGetKeyValueStoreValueSize(self.handle) + + @property + def data_size(self) -> bool: + """Length of serialized data (read-only)""" + return core.BNGetKeyValueStoreDataSize(self.handle) + + @property + def value_storage_size(self) -> bool: + """Size of all data in storage (read-only)""" + return core.BNGetKeyValueStoreValueStorageSize(self.handle) + + @property + def namespace_size(self) -> bool: + """Number of namespaces pushed with begin_namespace (read-only)""" + return core.BNGetKeyValueStoreNamespaceSize(self.handle) class Snapshot: - """ + """ ``class Snapshot`` is a model of an individual database snapshot, created on save. """ - def __init__(self, handle): - self.handle = core.handle_of_type(handle, core.BNSnapshot) - - def __del__(self): - core.BNFreeSnapshot(self.handle) - - @property - def database(self) -> 'Database': - """Get the owning database (read-only)""" - return Database(handle=core.BNGetSnapshotDatabase(self.handle)) - - @property - def id(self) -> int: - """Get the numerical id (read-only)""" - return core.BNGetSnapshotId(self.handle) - - @property - def name(self) -> str: - """Get the displayed snapshot name (read-only)""" - return core.BNGetSnapshotName(self.handle) - - @property - def is_auto_save(self) -> bool: - """If the snapshot was the result of an auto-save (read-only)""" - return core.BNIsSnapshotAutoSave(self.handle) - - @property - def has_contents(self) -> bool: - """If the snapshot has contents, and has not been trimmed (read-only)""" - return core.BNSnapshotHasContents(self.handle) - - @property - def has_undo(self) -> bool: - """If the snapshot has undo data (read-only)""" - return core.BNSnapshotHasUndo(self.handle) - - @property - def first_parent(self) -> Optional['Snapshot']: - """Get the first parent of the snapshot, or None if it has no parents (read-only)""" - handle = core.BNGetSnapshotFirstParent(self.handle) - if handle is None: - return None - return Snapshot(handle=handle) - - @property - def parents(self) -> List['Snapshot']: - """Get a list of all parent snapshots of the snapshot (read-only)""" - count = ctypes.c_ulonglong(0) - parents = core.BNGetSnapshotParents(self.handle, count) - - result = [] - try: - for i in range(0, count.value): - handle = core.BNNewSnapshotReference(parents[i]) - result.append(Snapshot(handle=handle)) - return result - finally: - core.BNFreeSnapshotList(parents, count) - - @property - def children(self) -> List['Snapshot']: - """Get a list of all child snapshots of the snapshot (read-only)""" - count = ctypes.c_ulonglong(0) - children = core.BNGetSnapshotChildren(self.handle, count) - - result = [] - try: - for i in range(0, count.value): - handle = core.BNNewSnapshotReference(children[i]) - result.append(Snapshot(handle=handle)) - return result - finally: - core.BNFreeSnapshotList(children, count) - - @property - def file_contents(self) -> databuffer.DataBuffer: - """Get a buffer of the raw data at the time of the snapshot (read-only)""" - assert self.has_contents - handle = core.BNGetSnapshotFileContents(self.handle) - assert handle is not None - return databuffer.DataBuffer(handle=handle) - - @property - def file_contents_hash(self) -> databuffer.DataBuffer: - """Get a hash of the data at the time of the snapshot (read-only)""" - assert self.has_contents - handle = core.BNGetSnapshotFileContentsHash(self.handle) - assert handle is not None - return databuffer.DataBuffer(handle=handle) - - @property - def undo_entries(self): - """Get a list of undo entries at the time of the snapshot (read-only)""" - assert self.has_undo - raise NotImplementedError("GetUndoEntries is not implemented in python") - - @property - def data(self) -> KeyValueStore: - """Get the backing kvs data with snapshot fields (read-only)""" - assert self.has_contents - handle = core.BNReadSnapshotData(self.handle) - assert handle is not None - return KeyValueStore(handle=handle) - - def has_ancestor(self, other: 'Snapshot') -> bool: - """Determine if this snapshot has another as an ancestor""" - return core.BNSnapshotHasAncestor(self.handle, other.handle) + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNSnapshot) + + def __del__(self): + core.BNFreeSnapshot(self.handle) + + @property + def database(self) -> 'Database': + """Get the owning database (read-only)""" + return Database(handle=core.BNGetSnapshotDatabase(self.handle)) + + @property + def id(self) -> int: + """Get the numerical id (read-only)""" + return core.BNGetSnapshotId(self.handle) + + @property + def name(self) -> str: + """Get the displayed snapshot name (read-only)""" + return core.BNGetSnapshotName(self.handle) + + @property + def is_auto_save(self) -> bool: + """If the snapshot was the result of an auto-save (read-only)""" + return core.BNIsSnapshotAutoSave(self.handle) + + @property + def has_contents(self) -> bool: + """If the snapshot has contents, and has not been trimmed (read-only)""" + return core.BNSnapshotHasContents(self.handle) + + @property + def has_undo(self) -> bool: + """If the snapshot has undo data (read-only)""" + return core.BNSnapshotHasUndo(self.handle) + + @property + def first_parent(self) -> Optional['Snapshot']: + """Get the first parent of the snapshot, or None if it has no parents (read-only)""" + handle = core.BNGetSnapshotFirstParent(self.handle) + if handle is None: + return None + return Snapshot(handle=handle) + + @property + def parents(self) -> List['Snapshot']: + """Get a list of all parent snapshots of the snapshot (read-only)""" + count = ctypes.c_ulonglong(0) + parents = core.BNGetSnapshotParents(self.handle, count) + + result = [] + try: + for i in range(0, count.value): + handle = core.BNNewSnapshotReference(parents[i]) + result.append(Snapshot(handle=handle)) + return result + finally: + core.BNFreeSnapshotList(parents, count) + + @property + def children(self) -> List['Snapshot']: + """Get a list of all child snapshots of the snapshot (read-only)""" + count = ctypes.c_ulonglong(0) + children = core.BNGetSnapshotChildren(self.handle, count) + + result = [] + try: + for i in range(0, count.value): + handle = core.BNNewSnapshotReference(children[i]) + result.append(Snapshot(handle=handle)) + return result + finally: + core.BNFreeSnapshotList(children, count) + + @property + def file_contents(self) -> databuffer.DataBuffer: + """Get a buffer of the raw data at the time of the snapshot (read-only)""" + assert self.has_contents + handle = core.BNGetSnapshotFileContents(self.handle) + assert handle is not None + return databuffer.DataBuffer(handle=handle) + + @property + def file_contents_hash(self) -> databuffer.DataBuffer: + """Get a hash of the data at the time of the snapshot (read-only)""" + assert self.has_contents + handle = core.BNGetSnapshotFileContentsHash(self.handle) + assert handle is not None + return databuffer.DataBuffer(handle=handle) + + @property + def undo_entries(self): + """Get a list of undo entries at the time of the snapshot (read-only)""" + assert self.has_undo + raise NotImplementedError("GetUndoEntries is not implemented in python") + + @property + def data(self) -> KeyValueStore: + """Get the backing kvs data with snapshot fields (read-only)""" + assert self.has_contents + handle = core.BNReadSnapshotData(self.handle) + assert handle is not None + return KeyValueStore(handle=handle) + + def has_ancestor(self, other: 'Snapshot') -> bool: + """Determine if this snapshot has another as an ancestor""" + return core.BNSnapshotHasAncestor(self.handle, other.handle) class Database: - """ + """ ``class Database`` provides lower level access to raw snapshot data used to construct analysis data """ - def __init__(self, handle): - self.handle = core.handle_of_type(handle, core.BNDatabase) - - def __del__(self): - core.BNFreeDatabase(self.handle) - - def __getitem__(self, item: int) -> Optional[Snapshot]: - return self.get_snapshot(item) - - def get_snapshot(self, id: int) -> Optional[Snapshot]: - """Get a snapshot by its id, or None if no snapshot with that id exists""" - snap = core.BNGetDatabaseSnapshot(self.handle, id) - if snap is None: - return None - return Snapshot(handle=snap) - - @property - def snapshots(self) -> List[Snapshot]: - """Get a list of all snapshots in the database (read-only)""" - count = ctypes.c_ulonglong(0) - snapshots = core.BNGetDatabaseSnapshots(self.handle, count) - assert snapshots is not None - - result = [] - try: - for i in range(0, count.value): - handle = core.BNNewSnapshotReference(snapshots[i]) - result.append(Snapshot(handle=handle)) - return result - finally: - core.BNFreeSnapshotList(snapshots, count) - - @property - def current_snapshot(self) -> Optional[Snapshot]: - """Get the current snapshot""" - snap = core.BNGetDatabaseCurrentSnapshot(self.handle) - if snap is None: - return None - return Snapshot(handle=snap) - - @current_snapshot.setter - def current_snapshot(self, value: Snapshot): - core.BNSetDatabaseCurrentSnapshot(self.handle, value.id) - - def remove_snapsot(self, id: int): - """Remove a snapshot in the database by id""" - core.BNRemoveDatabaseSnapshot(self.handle, id) - - @property - def global_keys(self) -> List[str]: - """Get a list of keys for all globals in the database (read-only)""" - count = ctypes.c_ulonglong(0) - value = core.BNGetDatabaseGlobalKeys(self.handle, count) - assert value is not None - - result = [] - try: - for i in range(0, count.value): - result.append(value[i]) - return result - finally: - core.BNFreeStringList(value, count) - - @property - def globals(self) -> Dict[str, str]: - """Get a dictionary of all globals (read-only)""" - count = ctypes.c_ulonglong(0) - value = core.BNGetDatabaseGlobalKeys(self.handle, count) - assert value is not None - - result = {} - try: - for i in range(0, count.value): - key = value[i] - result[key] = self.read_global(key) - return result - finally: - core.BNFreeStringList(value, count) - - def read_global(self, key: str) -> str: - """Get a specific global by key""" - value = core.BNReadDatabaseGlobal(self.handle, key) - assert value is not None - return value - - def write_global(self, key: str, value: str): - """Write a global into the database""" - core.BNWriteDatabaseGlobal(self.handle, key, value) - - def read_global_data(self, key: str) -> databuffer.DataBuffer: - """Get a specific global by key, as a binary buffer""" - handle = core.BNReadDatabaseGlobalData(self.handle, key) - assert handle is not None - return databuffer.DataBuffer(handle=handle) - - def write_global_data(self, key: str, value: databuffer.DataBuffer): - """Write a binary buffer into a global in the database""" - core.BNWriteDatabaseGlobalData(self.handle, key, value.handle) - - @property - def file(self) -> 'filemetadata.FileMetadata': - """Get the owning FileMetadata (read-only)""" - handle = core.BNGetDatabaseFile(self.handle) - assert handle is not None - return filemetadata.FileMetadata(handle=handle) - - @property - def analysis_cache(self) -> KeyValueStore: - """Get the backing analysis cache kvs (read-only)""" - handle = core.BNReadDatabaseAnalysisCache(self.handle) - assert handle is not None - return KeyValueStore(handle=handle) + def __init__(self, handle): + self.handle = core.handle_of_type(handle, core.BNDatabase) + + def __del__(self): + core.BNFreeDatabase(self.handle) + + def __getitem__(self, item: int) -> Optional[Snapshot]: + return self.get_snapshot(item) + + def get_snapshot(self, id: int) -> Optional[Snapshot]: + """Get a snapshot by its id, or None if no snapshot with that id exists""" + snap = core.BNGetDatabaseSnapshot(self.handle, id) + if snap is None: + return None + return Snapshot(handle=snap) + + @property + def snapshots(self) -> List[Snapshot]: + """Get a list of all snapshots in the database (read-only)""" + count = ctypes.c_ulonglong(0) + snapshots = core.BNGetDatabaseSnapshots(self.handle, count) + assert snapshots is not None + + result = [] + try: + for i in range(0, count.value): + handle = core.BNNewSnapshotReference(snapshots[i]) + result.append(Snapshot(handle=handle)) + return result + finally: + core.BNFreeSnapshotList(snapshots, count) + + @property + def current_snapshot(self) -> Optional[Snapshot]: + """Get the current snapshot""" + snap = core.BNGetDatabaseCurrentSnapshot(self.handle) + if snap is None: + return None + return Snapshot(handle=snap) + + @current_snapshot.setter + def current_snapshot(self, value: Snapshot): + core.BNSetDatabaseCurrentSnapshot(self.handle, value.id) + + def remove_snapsot(self, id: int): + """Remove a snapshot in the database by id""" + core.BNRemoveDatabaseSnapshot(self.handle, id) + + @property + def global_keys(self) -> List[str]: + """Get a list of keys for all globals in the database (read-only)""" + count = ctypes.c_ulonglong(0) + value = core.BNGetDatabaseGlobalKeys(self.handle, count) + assert value is not None + + result = [] + try: + for i in range(0, count.value): + result.append(value[i]) + return result + finally: + core.BNFreeStringList(value, count) + + @property + def globals(self) -> Dict[str, str]: + """Get a dictionary of all globals (read-only)""" + count = ctypes.c_ulonglong(0) + value = core.BNGetDatabaseGlobalKeys(self.handle, count) + assert value is not None + + result = {} + try: + for i in range(0, count.value): + key = value[i] + result[key] = self.read_global(key) + return result + finally: + core.BNFreeStringList(value, count) + + def read_global(self, key: str) -> str: + """Get a specific global by key""" + value = core.BNReadDatabaseGlobal(self.handle, key) + assert value is not None + return value + + def write_global(self, key: str, value: str): + """Write a global into the database""" + core.BNWriteDatabaseGlobal(self.handle, key, value) + + def read_global_data(self, key: str) -> databuffer.DataBuffer: + """Get a specific global by key, as a binary buffer""" + handle = core.BNReadDatabaseGlobalData(self.handle, key) + assert handle is not None + return databuffer.DataBuffer(handle=handle) + + def write_global_data(self, key: str, value: databuffer.DataBuffer): + """Write a binary buffer into a global in the database""" + core.BNWriteDatabaseGlobalData(self.handle, key, value.handle) + + @property + def file(self) -> 'filemetadata.FileMetadata': + """Get the owning FileMetadata (read-only)""" + handle = core.BNGetDatabaseFile(self.handle) + assert handle is not None + return filemetadata.FileMetadata(handle=handle) + + @property + def analysis_cache(self) -> KeyValueStore: + """Get the backing analysis cache kvs (read-only)""" + handle = core.BNReadDatabaseAnalysisCache(self.handle) + assert handle is not None + return KeyValueStore(handle=handle) diff --git a/python/databuffer.py b/python/databuffer.py index df16cc54..f4905cbd 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -25,8 +25,10 @@ from typing import Optional, Union from . import _binaryninjacore as core DataBufferInputType = Union[str, bytes, 'DataBuffer', int] + + class DataBuffer: - def __init__(self, contents:Union[str, bytes, 'DataBuffer', int]=b"", handle=None): + def __init__(self, contents: Union[str, bytes, 'DataBuffer', int] = b"", handle=None): if handle is not None: self.handle = core.handle_of_type(handle, core.BNDataBuffer) elif isinstance(contents, int): @@ -147,24 +149,24 @@ class DataBuffer: return core.BNDataBufferToBase64(self.handle) def base64_decode(self) -> 'DataBuffer': - return DataBuffer(handle = core.BNDecodeBase64(str(self))) + return DataBuffer(handle=core.BNDecodeBase64(str(self))) def zlib_compress(self) -> Optional['DataBuffer']: buf = core.BNZlibCompress(self.handle) if buf is None: return None - return DataBuffer(handle = buf) + return DataBuffer(handle=buf) def zlib_decompress(self) -> Optional['DataBuffer']: buf = core.BNZlibDecompress(self.handle) if buf is None: return None - return DataBuffer(handle = buf) + return DataBuffer(handle=buf) -def escape_string(text:bytes) -> str: +def escape_string(text: bytes) -> str: return DataBuffer(text).escape() -def unescape_string(text:bytes) -> 'DataBuffer': +def unescape_string(text: bytes) -> 'DataBuffer': return DataBuffer(text).unescape() diff --git a/python/dataclasses.py b/python/dataclasses.py index ddd59c66..9bfab21c 100644 --- a/python/dataclasses.py +++ b/python/dataclasses.py @@ -5,21 +5,12 @@ import types import inspect import keyword -__all__ = ['dataclass', - 'field', - 'Field', - 'FrozenInstanceError', - 'InitVar', - 'MISSING', - - # Helper functions. - 'fields', - 'asdict', - 'astuple', - 'make_dataclass', - 'replace', - 'is_dataclass', - ] +__all__ = [ + 'dataclass', 'field', 'Field', 'FrozenInstanceError', 'InitVar', 'MISSING', + + # Helper functions. + 'fields', 'asdict', 'astuple', 'make_dataclass', 'replace', 'is_dataclass', +] # Conditions for adding methods. The boxes indicate what action the # dataclass decorator takes. For all of these tables, when I talk @@ -66,7 +57,6 @@ __all__ = ['dataclass', # | True | add | | <- the default # +=======+=======+=======+ - # __setattr__ # __delattr__ # @@ -148,32 +138,43 @@ __all__ = ['dataclass', # Raised when an attempt is made to modify a frozen class. -class FrozenInstanceError(AttributeError): pass +class FrozenInstanceError(AttributeError): + pass + # A sentinel object for default values to signal that a default # factory will be used. This is given a nice repr() which will appear # in the function signature of dataclasses' constructors. class _HAS_DEFAULT_FACTORY_CLASS: - def __repr__(self): - return '' + def __repr__(self): + return '' + + _HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS() + # A sentinel object to detect if a parameter is supplied or not. Use # a class to give it a better repr. class _MISSING_TYPE: - pass + pass + + MISSING = _MISSING_TYPE() # Since most per-field metadata will be unused, create an empty # read-only proxy that can be shared among all fields. _EMPTY_METADATA = types.MappingProxyType({}) + # Markers for the various kinds of fields and pseudo-fields. class _FIELD_BASE: - def __init__(self, name): - self.name = name - def __repr__(self): - return self.name + def __init__(self, name): + self.name = name + + def __repr__(self): + return self.name + + _FIELD = _FIELD_BASE('_FIELD') _FIELD_CLASSVAR = _FIELD_BASE('_FIELD_CLASSVAR') _FIELD_INITVAR = _FIELD_BASE('_FIELD_INITVAR') @@ -195,12 +196,14 @@ _POST_INIT_NAME = '__post_init__' # https://bugs.python.org/issue33453 for details. _MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') + class _InitVarMeta(type): - def __getitem__(self, params): - return self + def __getitem__(self, params): + return self + class InitVar(metaclass=_InitVarMeta): - pass + pass # Instances of Field are only ever created from within this module, @@ -214,97 +217,86 @@ class InitVar(metaclass=_InitVarMeta): # When cls._FIELDS is filled in with a list of Field objects, the name # and type fields will have been populated. class Field: - __slots__ = ('name', - 'type', - 'default', - 'default_factory', - 'repr', - 'hash', - 'init', - 'compare', - 'metadata', - '_field_type', # Private: not to be used by user code. - ) - - def __init__(self, default, default_factory, init, repr, hash, compare, - metadata): - self.name = None - self.type = None - self.default = default - self.default_factory = default_factory - self.init = init - self.repr = repr - self.hash = hash - self.compare = compare - self.metadata = (_EMPTY_METADATA - if metadata is None or len(metadata) == 0 else - types.MappingProxyType(metadata)) - self._field_type = None - - def __repr__(self): - return ('Field(' - f'name={self.name!r},' - f'type={self.type!r},' - f'default={self.default!r},' - f'default_factory={self.default_factory!r},' - f'init={self.init!r},' - f'repr={self.repr!r},' - f'hash={self.hash!r},' - f'compare={self.compare!r},' - f'metadata={self.metadata!r},' - f'_field_type={self._field_type}' - ')') - - # This is used to support the PEP 487 __set_name__ protocol in the - # case where we're using a field that contains a descriptor as a - # defaul value. For details on __set_name__, see - # https://www.python.org/dev/peps/pep-0487/#implementation-details. - # - # Note that in _process_class, this Field object is overwritten - # with the default value, so the end result is a descriptor that - # had __set_name__ called on it at the right time. - def __set_name__(self, owner, name): - func = getattr(type(self.default), '__set_name__', None) - if func: - # There is a __set_name__ method on the descriptor, call - # it. - func(self.default, owner, name) + __slots__ = ( + 'name', 'type', 'default', 'default_factory', 'repr', 'hash', 'init', 'compare', 'metadata', + '_field_type', # Private: not to be used by user code. + ) + + def __init__(self, default, default_factory, init, repr, hash, compare, metadata): + self.name = None + self.type = None + self.default = default + self.default_factory = default_factory + self.init = init + self.repr = repr + self.hash = hash + self.compare = compare + self.metadata = ( + _EMPTY_METADATA if metadata is None or len(metadata) == 0 else types.MappingProxyType(metadata) + ) + self._field_type = None + + def __repr__(self): + return ( + 'Field(' + f'name={self.name!r},' + f'type={self.type!r},' + f'default={self.default!r},' + f'default_factory={self.default_factory!r},' + f'init={self.init!r},' + f'repr={self.repr!r},' + f'hash={self.hash!r},' + f'compare={self.compare!r},' + f'metadata={self.metadata!r},' + f'_field_type={self._field_type}' + ')' + ) + + # This is used to support the PEP 487 __set_name__ protocol in the + # case where we're using a field that contains a descriptor as a + # defaul value. For details on __set_name__, see + # https://www.python.org/dev/peps/pep-0487/#implementation-details. + # + # Note that in _process_class, this Field object is overwritten + # with the default value, so the end result is a descriptor that + # had __set_name__ called on it at the right time. + def __set_name__(self, owner, name): + func = getattr(type(self.default), '__set_name__', None) + if func: + # There is a __set_name__ method on the descriptor, call + # it. + func(self.default, owner, name) class _DataclassParams: - __slots__ = ('init', - 'repr', - 'eq', - 'order', - 'unsafe_hash', - 'frozen', - ) - - def __init__(self, init, repr, eq, order, unsafe_hash, frozen): - self.init = init - self.repr = repr - self.eq = eq - self.order = order - self.unsafe_hash = unsafe_hash - self.frozen = frozen - - def __repr__(self): - return ('_DataclassParams(' - f'init={self.init!r},' - f'repr={self.repr!r},' - f'eq={self.eq!r},' - f'order={self.order!r},' - f'unsafe_hash={self.unsafe_hash!r},' - f'frozen={self.frozen!r}' - ')') + __slots__ = ('init', 'repr', 'eq', 'order', 'unsafe_hash', 'frozen', ) + + def __init__(self, init, repr, eq, order, unsafe_hash, frozen): + self.init = init + self.repr = repr + self.eq = eq + self.order = order + self.unsafe_hash = unsafe_hash + self.frozen = frozen + + def __repr__(self): + return ( + '_DataclassParams(' + f'init={self.init!r},' + f'repr={self.repr!r},' + f'eq={self.eq!r},' + f'order={self.order!r},' + f'unsafe_hash={self.unsafe_hash!r},' + f'frozen={self.frozen!r}' + ')' + ) # This function is used instead of exposing Field creation directly, # so that a type checker can be told (via overloads) that this is a # function whose type depends on its parameters. -def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, - hash=None, compare=True, metadata=None): - """Return an object to identify dataclass fields. +def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None): + """Return an object to identify dataclass fields. default is the default value of the field. default_factory is a 0-argument function called to initialize a field's value. If init @@ -318,392 +310,386 @@ def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, It is an error to specify both default and default_factory. """ - if default is not MISSING and default_factory is not MISSING: - raise ValueError('cannot specify both default and default_factory') - return Field(default, default_factory, init, repr, hash, compare, - metadata) + if default is not MISSING and default_factory is not MISSING: + raise ValueError('cannot specify both default and default_factory') + return Field(default, default_factory, init, repr, hash, compare, metadata) def _tuple_str(obj_name, fields): - # Return a string representing each field of obj_name as a tuple - # member. So, if fields is ['x', 'y'] and obj_name is "self", - # return "(self.x,self.y)". - - # Special case for the 0-tuple. - if not fields: - return '()' - # Note the trailing comma, needed if this turns out to be a 1-tuple. - return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)' - - -def _create_fn(name, args, body, *, globals=None, locals=None, - return_type=MISSING): - # Note that we mutate locals when exec() is called. Caller - # beware! The only callers are internal to this module, so no - # worries about external callers. - if locals is None: - locals = {} - return_annotation = '' - if return_type is not MISSING: - locals['_return_type'] = return_type - return_annotation = '->_return_type' - args = ','.join(args) - body = '\n'.join(f' {b}' for b in body) - - # Compute the text of the entire function. - txt = f'def {name}({args}){return_annotation}:\n{body}' - - exec(txt, globals, locals) - return locals[name] + # Return a string representing each field of obj_name as a tuple + # member. So, if fields is ['x', 'y'] and obj_name is "self", + # return "(self.x,self.y)". + + # Special case for the 0-tuple. + if not fields: + return '()' + # Note the trailing comma, needed if this turns out to be a 1-tuple. + return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)' + + +def _create_fn(name, args, body, *, globals=None, locals=None, return_type=MISSING): + # Note that we mutate locals when exec() is called. Caller + # beware! The only callers are internal to this module, so no + # worries about external callers. + if locals is None: + locals = {} + return_annotation = '' + if return_type is not MISSING: + locals['_return_type'] = return_type + return_annotation = '->_return_type' + args = ','.join(args) + body = '\n'.join(f' {b}' for b in body) + + # Compute the text of the entire function. + txt = f'def {name}({args}){return_annotation}:\n{body}' + + exec(txt, globals, locals) + return locals[name] def _field_assign(frozen, name, value, self_name): - # If we're a frozen class, then assign to our fields in __init__ - # via object.__setattr__. Otherwise, just use a simple - # assignment. - # - # self_name is what "self" is called in this function: don't - # hard-code "self", since that might be a field name. - if frozen: - return f'object.__setattr__({self_name},{name!r},{value})' - return f'{self_name}.{name}={value}' + # If we're a frozen class, then assign to our fields in __init__ + # via object.__setattr__. Otherwise, just use a simple + # assignment. + # + # self_name is what "self" is called in this function: don't + # hard-code "self", since that might be a field name. + if frozen: + return f'object.__setattr__({self_name},{name!r},{value})' + return f'{self_name}.{name}={value}' def _field_init(f, frozen, globals, self_name): - # Return the text of the line in the body of __init__ that will - # initialize this field. - - default_name = f'_dflt_{f.name}' - if f.default_factory is not MISSING: - if f.init: - # This field has a default factory. If a parameter is - # given, use it. If not, call the factory. - globals[default_name] = f.default_factory - value = (f'{default_name}() ' - f'if {f.name} is _HAS_DEFAULT_FACTORY ' - f'else {f.name}') - else: - # This is a field that's not in the __init__ params, but - # has a default factory function. It needs to be - # initialized here by calling the factory function, - # because there's no other way to initialize it. - - # For a field initialized with a default=defaultvalue, the - # class dict just has the default value - # (cls.fieldname=defaultvalue). But that won't work for a - # default factory, the factory must be called in __init__ - # and we must assign that to self.fieldname. We can't - # fall back to the class dict's value, both because it's - # not set, and because it might be different per-class - # (which, after all, is why we have a factory function!). - - globals[default_name] = f.default_factory - value = f'{default_name}()' - else: - # No default factory. - if f.init: - if f.default is MISSING: - # There's no default, just do an assignment. - value = f.name - elif f.default is not MISSING: - globals[default_name] = f.default - value = f.name - else: - # This field does not need initialization. Signify that - # to the caller by returning None. - return None - - # Only test this now, so that we can create variables for the - # default. However, return None to signify that we're not going - # to actually do the assignment statement for InitVars. - if f._field_type is _FIELD_INITVAR: - return None - - # Now, actually generate the field assignment. - return _field_assign(frozen, f.name, value, self_name) + # Return the text of the line in the body of __init__ that will + # initialize this field. + + default_name = f'_dflt_{f.name}' + if f.default_factory is not MISSING: + if f.init: + # This field has a default factory. If a parameter is + # given, use it. If not, call the factory. + globals[default_name] = f.default_factory + value = (f'{default_name}() ' + f'if {f.name} is _HAS_DEFAULT_FACTORY ' + f'else {f.name}') + else: + # This is a field that's not in the __init__ params, but + # has a default factory function. It needs to be + # initialized here by calling the factory function, + # because there's no other way to initialize it. + + # For a field initialized with a default=defaultvalue, the + # class dict just has the default value + # (cls.fieldname=defaultvalue). But that won't work for a + # default factory, the factory must be called in __init__ + # and we must assign that to self.fieldname. We can't + # fall back to the class dict's value, both because it's + # not set, and because it might be different per-class + # (which, after all, is why we have a factory function!). + + globals[default_name] = f.default_factory + value = f'{default_name}()' + else: + # No default factory. + if f.init: + if f.default is MISSING: + # There's no default, just do an assignment. + value = f.name + elif f.default is not MISSING: + globals[default_name] = f.default + value = f.name + else: + # This field does not need initialization. Signify that + # to the caller by returning None. + return None + + # Only test this now, so that we can create variables for the + # default. However, return None to signify that we're not going + # to actually do the assignment statement for InitVars. + if f._field_type is _FIELD_INITVAR: + return None + + # Now, actually generate the field assignment. + return _field_assign(frozen, f.name, value, self_name) def _init_param(f): - # Return the __init__ parameter string for this field. For - # example, the equivalent of 'x:int=3' (except instead of 'int', - # reference a variable set to int, and instead of '3', reference a - # variable set to 3). - if f.default is MISSING and f.default_factory is MISSING: - # There's no default, and no default_factory, just output the - # variable name and type. - default = '' - elif f.default is not MISSING: - # There's a default, this will be the name that's used to look - # it up. - default = f'=_dflt_{f.name}' - elif f.default_factory is not MISSING: - # There's a factory function. Set a marker. - default = '=_HAS_DEFAULT_FACTORY' - return f'{f.name}:_type_{f.name}{default}' + # Return the __init__ parameter string for this field. For + # example, the equivalent of 'x:int=3' (except instead of 'int', + # reference a variable set to int, and instead of '3', reference a + # variable set to 3). + if f.default is MISSING and f.default_factory is MISSING: + # There's no default, and no default_factory, just output the + # variable name and type. + default = '' + elif f.default is not MISSING: + # There's a default, this will be the name that's used to look + # it up. + default = f'=_dflt_{f.name}' + elif f.default_factory is not MISSING: + # There's a factory function. Set a marker. + default = '=_HAS_DEFAULT_FACTORY' + return f'{f.name}:_type_{f.name}{default}' def _init_fn(fields, frozen, has_post_init, self_name): - # fields contains both real fields and InitVar pseudo-fields. - - # Make sure we don't have fields without defaults following fields - # with defaults. This actually would be caught when exec-ing the - # function source code, but catching it here gives a better error - # message, and future-proofs us in case we build up the function - # using ast. - seen_default = False - for f in fields: - # Only consider fields in the __init__ call. - if f.init: - if not (f.default is MISSING and f.default_factory is MISSING): - seen_default = True - elif seen_default: - raise TypeError(f'non-default argument {f.name!r} ' - 'follows default argument') - - globals = {'MISSING': MISSING, - '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY} - - body_lines = [] - for f in fields: - line = _field_init(f, frozen, globals, self_name) - # line is None means that this field doesn't require - # initialization (it's a pseudo-field). Just skip it. - if line: - body_lines.append(line) - - # Does this class have a post-init function? - if has_post_init: - params_str = ','.join(f.name for f in fields - if f._field_type is _FIELD_INITVAR) - body_lines.append(f'{self_name}.{_POST_INIT_NAME}({params_str})') - - # If no body lines, use 'pass'. - if not body_lines: - body_lines = ['pass'] - - locals = {f'_type_{f.name}': f.type for f in fields} - return _create_fn('__init__', - [self_name] + [_init_param(f) for f in fields if f.init], - body_lines, - locals=locals, - globals=globals, - return_type=None) + # fields contains both real fields and InitVar pseudo-fields. + + # Make sure we don't have fields without defaults following fields + # with defaults. This actually would be caught when exec-ing the + # function source code, but catching it here gives a better error + # message, and future-proofs us in case we build up the function + # using ast. + seen_default = False + for f in fields: + # Only consider fields in the __init__ call. + if f.init: + if not (f.default is MISSING and f.default_factory is MISSING): + seen_default = True + elif seen_default: + raise TypeError(f'non-default argument {f.name!r} ' + 'follows default argument') + + globals = {'MISSING': MISSING, '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY} + + body_lines = [] + for f in fields: + line = _field_init(f, frozen, globals, self_name) + # line is None means that this field doesn't require + # initialization (it's a pseudo-field). Just skip it. + if line: + body_lines.append(line) + + # Does this class have a post-init function? + if has_post_init: + params_str = ','.join(f.name for f in fields if f._field_type is _FIELD_INITVAR) + body_lines.append(f'{self_name}.{_POST_INIT_NAME}({params_str})') + + # If no body lines, use 'pass'. + if not body_lines: + body_lines = ['pass'] + + locals = {f'_type_{f.name}': f.type for f in fields} + return _create_fn( + '__init__', [self_name] + [_init_param(f) for f in fields if f.init], body_lines, locals=locals, + globals=globals, return_type=None + ) def _repr_fn(fields): - return _create_fn('__repr__', - ('self',), - ['return self.__class__.__qualname__ + f"(' + - ', '.join([f"{f.name}={{self.{f.name}!r}}" - for f in fields]) + - ')"']) + return _create_fn( + '__repr__', ('self', ), [ + 'return self.__class__.__qualname__ + f"(' + ', '.join([f"{f.name}={{self.{f.name}!r}}" + for f in fields]) + ')"' + ] + ) def _frozen_get_del_attr(cls, fields): - # XXX: globals is modified on the first call to _create_fn, then - # the modified version is used in the second call. Is this okay? - globals = {'cls': cls, - 'FrozenInstanceError': FrozenInstanceError} - if fields: - fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)' - else: - # Special case for the zero-length tuple. - fields_str = '()' - return (_create_fn('__setattr__', - ('self', 'name', 'value'), - (f'if type(self) is cls or name in {fields_str}:', - ' raise FrozenInstanceError(f"cannot assign to field {name!r}")', - f'super(cls, self).__setattr__(name, value)'), - globals=globals), - _create_fn('__delattr__', - ('self', 'name'), - (f'if type(self) is cls or name in {fields_str}:', - ' raise FrozenInstanceError(f"cannot delete field {name!r}")', - f'super(cls, self).__delattr__(name)'), - globals=globals), - ) + # XXX: globals is modified on the first call to _create_fn, then + # the modified version is used in the second call. Is this okay? + globals = {'cls': cls, 'FrozenInstanceError': FrozenInstanceError} + if fields: + fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)' + else: + # Special case for the zero-length tuple. + fields_str = '()' + return ( + _create_fn( + '__setattr__', ('self', 'name', 'value'), ( + f'if type(self) is cls or name in {fields_str}:', + ' raise FrozenInstanceError(f"cannot assign to field {name!r}")', + f'super(cls, self).__setattr__(name, value)' + ), globals=globals + ), + _create_fn( + '__delattr__', ('self', 'name'), ( + f'if type(self) is cls or name in {fields_str}:', + ' raise FrozenInstanceError(f"cannot delete field {name!r}")', f'super(cls, self).__delattr__(name)' + ), globals=globals + ), + ) def _cmp_fn(name, op, self_tuple, other_tuple): - # Create a comparison function. If the fields in the object are - # named 'x' and 'y', then self_tuple is the string - # '(self.x,self.y)' and other_tuple is the string - # '(other.x,other.y)'. + # Create a comparison function. If the fields in the object are + # named 'x' and 'y', then self_tuple is the string + # '(self.x,self.y)' and other_tuple is the string + # '(other.x,other.y)'. - return _create_fn(name, - ('self', 'other'), - [ 'if other.__class__ is self.__class__:', - f' return {self_tuple}{op}{other_tuple}', - 'return NotImplemented']) + return _create_fn( + name, ('self', 'other'), + ['if other.__class__ is self.__class__:', f' return {self_tuple}{op}{other_tuple}', 'return NotImplemented'] + ) def _hash_fn(fields): - self_tuple = _tuple_str('self', fields) - return _create_fn('__hash__', - ('self',), - [f'return hash({self_tuple})']) + self_tuple = _tuple_str('self', fields) + return _create_fn('__hash__', ('self', ), [f'return hash({self_tuple})']) def _is_classvar(a_type, typing): - # This test uses a typing internal class, but it's the best way to - # test if this is a ClassVar. - return type(a_type) is typing._ClassVar + # This test uses a typing internal class, but it's the best way to + # test if this is a ClassVar. + return type(a_type) is typing._ClassVar def _is_initvar(a_type, dataclasses): - # The module we're checking against is the module we're - # currently in (dataclasses.py). - return a_type is dataclasses.InitVar + # The module we're checking against is the module we're + # currently in (dataclasses.py). + return a_type is dataclasses.InitVar def _is_type(annotation, cls, a_module, a_type, is_type_predicate): - # Given a type annotation string, does it refer to a_type in - # a_module? For example, when checking that annotation denotes a - # ClassVar, then a_module is typing, and a_type is - # typing.ClassVar. - - # It's possible to look up a_module given a_type, but it involves - # looking in sys.modules (again!), and seems like a waste since - # the caller already knows a_module. - - # - annotation is a string type annotation - # - cls is the class that this annotation was found in - # - a_module is the module we want to match - # - a_type is the type in that module we want to match - # - is_type_predicate is a function called with (obj, a_module) - # that determines if obj is of the desired type. - - # Since this test does not do a local namespace lookup (and - # instead only a module (global) lookup), there are some things it - # gets wrong. - - # With string annotations, cv0 will be detected as a ClassVar: - # CV = ClassVar - # @dataclass - # class C0: - # cv0: CV - - # But in this example cv1 will not be detected as a ClassVar: - # @dataclass - # class C1: - # CV = ClassVar - # cv1: CV - - # In C1, the code in this function (_is_type) will look up "CV" in - # the module and not find it, so it will not consider cv1 as a - # ClassVar. This is a fairly obscure corner case, and the best - # way to fix it would be to eval() the string "CV" with the - # correct global and local namespaces. However that would involve - # a eval() penalty for every single field of every dataclass - # that's defined. It was judged not worth it. - - match = _MODULE_IDENTIFIER_RE.match(annotation) - if match: - ns = None - module_name = match.group(1) - if not module_name: - # No module name, assume the class's module did - # "from dataclasses import InitVar". - ns = sys.modules.get(cls.__module__).__dict__ - else: - # Look up module_name in the class's module. - module = sys.modules.get(cls.__module__) - if module and module.__dict__.get(module_name) is a_module: - ns = sys.modules.get(a_type.__module__).__dict__ - if ns and is_type_predicate(ns.get(match.group(2)), a_module): - return True - return False + # Given a type annotation string, does it refer to a_type in + # a_module? For example, when checking that annotation denotes a + # ClassVar, then a_module is typing, and a_type is + # typing.ClassVar. + + # It's possible to look up a_module given a_type, but it involves + # looking in sys.modules (again!), and seems like a waste since + # the caller already knows a_module. + + # - annotation is a string type annotation + # - cls is the class that this annotation was found in + # - a_module is the module we want to match + # - a_type is the type in that module we want to match + # - is_type_predicate is a function called with (obj, a_module) + # that determines if obj is of the desired type. + + # Since this test does not do a local namespace lookup (and + # instead only a module (global) lookup), there are some things it + # gets wrong. + + # With string annotations, cv0 will be detected as a ClassVar: + # CV = ClassVar + # @dataclass + # class C0: + # cv0: CV + + # But in this example cv1 will not be detected as a ClassVar: + # @dataclass + # class C1: + # CV = ClassVar + # cv1: CV + + # In C1, the code in this function (_is_type) will look up "CV" in + # the module and not find it, so it will not consider cv1 as a + # ClassVar. This is a fairly obscure corner case, and the best + # way to fix it would be to eval() the string "CV" with the + # correct global and local namespaces. However that would involve + # a eval() penalty for every single field of every dataclass + # that's defined. It was judged not worth it. + + match = _MODULE_IDENTIFIER_RE.match(annotation) + if match: + ns = None + module_name = match.group(1) + if not module_name: + # No module name, assume the class's module did + # "from dataclasses import InitVar". + ns = sys.modules.get(cls.__module__).__dict__ + else: + # Look up module_name in the class's module. + module = sys.modules.get(cls.__module__) + if module and module.__dict__.get(module_name) is a_module: + ns = sys.modules.get(a_type.__module__).__dict__ + if ns and is_type_predicate(ns.get(match.group(2)), a_module): + return True + return False def _get_field(cls, a_name, a_type): - # Return a Field object for this field name and type. ClassVars - # and InitVars are also returned, but marked as such (see - # f._field_type). - - # If the default value isn't derived from Field, then it's only a - # normal default value. Convert it to a Field(). - default = getattr(cls, a_name, MISSING) - if isinstance(default, Field): - f = default - else: - if isinstance(default, types.MemberDescriptorType): - # This is a field in __slots__, so it has no default value. - default = MISSING - f = field(default=default) - - # Only at this point do we know the name and the type. Set them. - f.name = a_name - f.type = a_type - - # Assume it's a normal field until proven otherwise. We're next - # going to decide if it's a ClassVar or InitVar, everything else - # is just a normal field. - f._field_type = _FIELD - - # In addition to checking for actual types here, also check for - # string annotations. get_type_hints() won't always work for us - # (see https://github.com/python/typing/issues/508 for example), - # plus it's expensive and would require an eval for every stirng - # annotation. So, make a best effort to see if this is a ClassVar - # or InitVar using regex's and checking that the thing referenced - # is actually of the correct type. - - # For the complete discussion, see https://bugs.python.org/issue33453 - - # If typing has not been imported, then it's impossible for any - # annotation to be a ClassVar. So, only look for ClassVar if - # typing has been imported by any module (not necessarily cls's - # module). - typing = sys.modules.get('typing') - if typing: - if (_is_classvar(a_type, typing) - or (isinstance(f.type, str) - and _is_type(f.type, cls, typing, typing.ClassVar, - _is_classvar))): - f._field_type = _FIELD_CLASSVAR - - # If the type is InitVar, or if it's a matching string annotation, - # then it's an InitVar. - if f._field_type is _FIELD: - # The module we're checking against is the module we're - # currently in (dataclasses.py). - dataclasses = sys.modules[__name__] - if (_is_initvar(a_type, dataclasses) - or (isinstance(f.type, str) - and _is_type(f.type, cls, dataclasses, dataclasses.InitVar, - _is_initvar))): - f._field_type = _FIELD_INITVAR - - # Validations for individual fields. This is delayed until now, - # instead of in the Field() constructor, since only here do we - # know the field name, which allows for better error reporting. - - # Special restrictions for ClassVar and InitVar. - if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR): - if f.default_factory is not MISSING: - raise TypeError(f'field {f.name} cannot have a ' - 'default factory') - # Should I check for other field settings? default_factory - # seems the most serious to check for. Maybe add others. For - # example, how about init=False (or really, - # init=)? It makes no sense for - # ClassVar and InitVar to specify init=. - - # For real fields, disallow mutable defaults for known types. - if f._field_type is _FIELD and isinstance(f.default, (list, dict, set)): - raise ValueError(f'mutable default {type(f.default)} for field ' - f'{f.name} is not allowed: use default_factory') - - return f + # Return a Field object for this field name and type. ClassVars + # and InitVars are also returned, but marked as such (see + # f._field_type). + + # If the default value isn't derived from Field, then it's only a + # normal default value. Convert it to a Field(). + default = getattr(cls, a_name, MISSING) + if isinstance(default, Field): + f = default + else: + if isinstance(default, types.MemberDescriptorType): + # This is a field in __slots__, so it has no default value. + default = MISSING + f = field(default=default) + + # Only at this point do we know the name and the type. Set them. + f.name = a_name + f.type = a_type + + # Assume it's a normal field until proven otherwise. We're next + # going to decide if it's a ClassVar or InitVar, everything else + # is just a normal field. + f._field_type = _FIELD + + # In addition to checking for actual types here, also check for + # string annotations. get_type_hints() won't always work for us + # (see https://github.com/python/typing/issues/508 for example), + # plus it's expensive and would require an eval for every stirng + # annotation. So, make a best effort to see if this is a ClassVar + # or InitVar using regex's and checking that the thing referenced + # is actually of the correct type. + + # For the complete discussion, see https://bugs.python.org/issue33453 + + # If typing has not been imported, then it's impossible for any + # annotation to be a ClassVar. So, only look for ClassVar if + # typing has been imported by any module (not necessarily cls's + # module). + typing = sys.modules.get('typing') + if typing: + if ( + _is_classvar(a_type, typing) + or (isinstance(f.type, str) and _is_type(f.type, cls, typing, typing.ClassVar, _is_classvar)) + ): + f._field_type = _FIELD_CLASSVAR + + # If the type is InitVar, or if it's a matching string annotation, + # then it's an InitVar. + if f._field_type is _FIELD: + # The module we're checking against is the module we're + # currently in (dataclasses.py). + dataclasses = sys.modules[__name__] + if ( + _is_initvar(a_type, dataclasses) + or (isinstance(f.type, str) and _is_type(f.type, cls, dataclasses, dataclasses.InitVar, _is_initvar)) + ): + f._field_type = _FIELD_INITVAR + + # Validations for individual fields. This is delayed until now, + # instead of in the Field() constructor, since only here do we + # know the field name, which allows for better error reporting. + + # Special restrictions for ClassVar and InitVar. + if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR): + if f.default_factory is not MISSING: + raise TypeError(f'field {f.name} cannot have a ' + 'default factory') + # Should I check for other field settings? default_factory + # seems the most serious to check for. Maybe add others. For + # example, how about init=False (or really, + # init=)? It makes no sense for + # ClassVar and InitVar to specify init=. + + # For real fields, disallow mutable defaults for known types. + if f._field_type is _FIELD and isinstance(f.default, (list, dict, set)): + raise ValueError( + f'mutable default {type(f.default)} for field ' + f'{f.name} is not allowed: use default_factory' + ) + + return f def _set_new_attribute(cls, name, value): - # Never overwrites an existing attribute. Returns True if the - # attribute already exists. - if name in cls.__dict__: - return True - setattr(cls, name, value) - return False + # Never overwrites an existing attribute. Returns True if the + # attribute already exists. + if name in cls.__dict__: + return True + setattr(cls, name, value) + return False # Decide if/how we're going to create a hash function. Key is @@ -711,17 +697,21 @@ def _set_new_attribute(cls, name, value): # take. The common case is to do nothing, so instead of providing a # function that is a no-op, use None to signify that. + def _hash_set_none(cls, fields): - return None + return None + def _hash_add(cls, fields): - flds = [f for f in fields if (f.compare if f.hash is None else f.hash)] - return _hash_fn(flds) + flds = [f for f in fields if (f.compare if f.hash is None else f.hash)] + return _hash_fn(flds) + def _hash_exception(cls, fields): - # Raise an exception. - raise TypeError(f'Cannot overwrite attribute __hash__ ' - f'in class {cls.__name__}') + # Raise an exception. + raise TypeError(f'Cannot overwrite attribute __hash__ ' + f'in class {cls.__name__}') + # # +-------------------------------------- unsafe_hash? @@ -733,208 +723,185 @@ def _hash_exception(cls, fields): # | | | | | # v v v v v _hash_action = {(False, False, False, False): None, - (False, False, False, True ): None, - (False, False, True, False): None, - (False, False, True, True ): None, - (False, True, False, False): _hash_set_none, - (False, True, False, True ): None, - (False, True, True, False): _hash_add, - (False, True, True, True ): None, - (True, False, False, False): _hash_add, - (True, False, False, True ): _hash_exception, - (True, False, True, False): _hash_add, - (True, False, True, True ): _hash_exception, - (True, True, False, False): _hash_add, - (True, True, False, True ): _hash_exception, - (True, True, True, False): _hash_add, - (True, True, True, True ): _hash_exception, - } + (False, False, False, True): None, (False, False, True, False): None, (False, False, True, True): None, + (False, True, False, False): _hash_set_none, (False, True, False, True): None, + (False, True, True, False): _hash_add, (False, True, True, True): None, + (True, False, False, False): _hash_add, (True, False, False, True): _hash_exception, + (True, False, True, False): _hash_add, (True, False, True, True): _hash_exception, + (True, True, False, False): _hash_add, (True, True, False, True): _hash_exception, + (True, True, True, False): _hash_add, (True, True, True, True): _hash_exception, } # See https://bugs.python.org/issue32929#msg312829 for an if-statement # version of this table. def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen): - # Now that dicts retain insertion order, there's no reason to use - # an ordered dict. I am leveraging that ordering here, because - # derived class fields overwrite base class fields, but the order - # is defined by the base class, which is found first. - fields = {} - - setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order, - unsafe_hash, frozen)) - - # Find our base classes in reverse MRO order, and exclude - # ourselves. In reversed order so that more derived classes - # override earlier field definitions in base classes. As long as - # we're iterating over them, see if any are frozen. - any_frozen_base = False - has_dataclass_bases = False - for b in cls.__mro__[-1:0:-1]: - # Only process classes that have been processed by our - # decorator. That is, they have a _FIELDS attribute. - base_fields = getattr(b, _FIELDS, None) - if base_fields: - has_dataclass_bases = True - for f in base_fields.values(): - fields[f.name] = f - if getattr(b, _PARAMS).frozen: - any_frozen_base = True - - # Annotations that are defined in this class (not in base - # classes). If __annotations__ isn't present, then this class - # adds no new annotations. We use this to compute fields that are - # added by this class. - # - # Fields are found from cls_annotations, which is guaranteed to be - # ordered. Default values are from class attributes, if a field - # has a default. If the default value is a Field(), then it - # contains additional info beyond (and possibly including) the - # actual default value. Pseudo-fields ClassVars and InitVars are - # included, despite the fact that they're not real fields. That's - # dealt with later. - cls_annotations = cls.__dict__.get('__annotations__', {}) - - # Now find fields in our class. While doing so, validate some - # things, and set the default values (as class attributes) where - # we can. - cls_fields = [_get_field(cls, name, type) - for name, type in cls_annotations.items()] - for f in cls_fields: - fields[f.name] = f - - # If the class attribute (which is the default value for this - # field) exists and is of type 'Field', replace it with the - # real default. This is so that normal class introspection - # sees a real default value, not a Field. - if isinstance(getattr(cls, f.name, None), Field): - if f.default is MISSING: - # If there's no default, delete the class attribute. - # This happens if we specify field(repr=False), for - # example (that is, we specified a field object, but - # no default value). Also if we're using a default - # factory. The class attribute should not be set at - # all in the post-processed class. - delattr(cls, f.name) - else: - setattr(cls, f.name, f.default) - - # Do we have any Field members that don't also have annotations? - for name, value in cls.__dict__.items(): - if isinstance(value, Field) and not name in cls_annotations: - raise TypeError(f'{name!r} is a field but has no type annotation') - - # Check rules that apply if we are derived from any dataclasses. - if has_dataclass_bases: - # Raise an exception if any of our bases are frozen, but we're not. - if any_frozen_base and not frozen: - raise TypeError('cannot inherit non-frozen dataclass from a ' - 'frozen one') - - # Raise an exception if we're frozen, but none of our bases are. - if not any_frozen_base and frozen: - raise TypeError('cannot inherit frozen dataclass from a ' - 'non-frozen one') - - # Remember all of the fields on our class (including bases). This - # also marks this class as being a dataclass. - setattr(cls, _FIELDS, fields) - - # Was this class defined with an explicit __hash__? Note that if - # __eq__ is defined in this class, then python will automatically - # set __hash__ to None. This is a heuristic, as it's possible - # that such a __hash__ == None was not auto-generated, but it - # close enough. - class_hash = cls.__dict__.get('__hash__', MISSING) - has_explicit_hash = not (class_hash is MISSING or - (class_hash is None and '__eq__' in cls.__dict__)) - - # If we're generating ordering methods, we must be generating the - # eq methods. - if order and not eq: - raise ValueError('eq must be true if order is true') - - if init: - # Does this class have a post-init function? - has_post_init = hasattr(cls, _POST_INIT_NAME) - - # Include InitVars and regular fields (so, not ClassVars). - flds = [f for f in fields.values() - if f._field_type in (_FIELD, _FIELD_INITVAR)] - _set_new_attribute(cls, '__init__', - _init_fn(flds, - frozen, - has_post_init, - # The name to use for the "self" - # param in __init__. Use "self" - # if possible. - '__dataclass_self__' if 'self' in fields - else 'self', - )) - - # Get the fields as a list, and include only real fields. This is - # used in all of the following methods. - field_list = [f for f in fields.values() if f._field_type is _FIELD] - - if repr: - flds = [f for f in field_list if f.repr] - _set_new_attribute(cls, '__repr__', _repr_fn(flds)) - - if eq: - # Create _eq__ method. There's no need for a __ne__ method, - # since python will call __eq__ and negate it. - flds = [f for f in field_list if f.compare] - self_tuple = _tuple_str('self', flds) - other_tuple = _tuple_str('other', flds) - _set_new_attribute(cls, '__eq__', - _cmp_fn('__eq__', '==', - self_tuple, other_tuple)) - - if order: - # Create and set the ordering methods. - flds = [f for f in field_list if f.compare] - self_tuple = _tuple_str('self', flds) - other_tuple = _tuple_str('other', flds) - for name, op in [('__lt__', '<'), - ('__le__', '<='), - ('__gt__', '>'), - ('__ge__', '>='), - ]: - if _set_new_attribute(cls, name, - _cmp_fn(name, op, self_tuple, other_tuple)): - raise TypeError(f'Cannot overwrite attribute {name} ' - f'in class {cls.__name__}. Consider using ' - 'functools.total_ordering') - - if frozen: - for fn in _frozen_get_del_attr(cls, field_list): - if _set_new_attribute(cls, fn.__name__, fn): - raise TypeError(f'Cannot overwrite attribute {fn.__name__} ' - f'in class {cls.__name__}') - - # Decide if/how we're going to create a hash function. - hash_action = _hash_action[bool(unsafe_hash), - bool(eq), - bool(frozen), - has_explicit_hash] - if hash_action: - # No need to call _set_new_attribute here, since by the time - # we're here the overwriting is unconditional. - cls.__hash__ = hash_action(cls, field_list) - - if not getattr(cls, '__doc__'): - # Create a class doc-string. - cls.__doc__ = (cls.__name__ + - str(inspect.signature(cls)).replace(' -> None', '')) - - return cls + # Now that dicts retain insertion order, there's no reason to use + # an ordered dict. I am leveraging that ordering here, because + # derived class fields overwrite base class fields, but the order + # is defined by the base class, which is found first. + fields = {} + + setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order, unsafe_hash, frozen)) + + # Find our base classes in reverse MRO order, and exclude + # ourselves. In reversed order so that more derived classes + # override earlier field definitions in base classes. As long as + # we're iterating over them, see if any are frozen. + any_frozen_base = False + has_dataclass_bases = False + for b in cls.__mro__[-1:0:-1]: + # Only process classes that have been processed by our + # decorator. That is, they have a _FIELDS attribute. + base_fields = getattr(b, _FIELDS, None) + if base_fields: + has_dataclass_bases = True + for f in base_fields.values(): + fields[f.name] = f + if getattr(b, _PARAMS).frozen: + any_frozen_base = True + + # Annotations that are defined in this class (not in base + # classes). If __annotations__ isn't present, then this class + # adds no new annotations. We use this to compute fields that are + # added by this class. + # + # Fields are found from cls_annotations, which is guaranteed to be + # ordered. Default values are from class attributes, if a field + # has a default. If the default value is a Field(), then it + # contains additional info beyond (and possibly including) the + # actual default value. Pseudo-fields ClassVars and InitVars are + # included, despite the fact that they're not real fields. That's + # dealt with later. + cls_annotations = cls.__dict__.get('__annotations__', {}) + + # Now find fields in our class. While doing so, validate some + # things, and set the default values (as class attributes) where + # we can. + cls_fields = [_get_field(cls, name, type) for name, type in cls_annotations.items()] + for f in cls_fields: + fields[f.name] = f + + # If the class attribute (which is the default value for this + # field) exists and is of type 'Field', replace it with the + # real default. This is so that normal class introspection + # sees a real default value, not a Field. + if isinstance(getattr(cls, f.name, None), Field): + if f.default is MISSING: + # If there's no default, delete the class attribute. + # This happens if we specify field(repr=False), for + # example (that is, we specified a field object, but + # no default value). Also if we're using a default + # factory. The class attribute should not be set at + # all in the post-processed class. + delattr(cls, f.name) + else: + setattr(cls, f.name, f.default) + + # Do we have any Field members that don't also have annotations? + for name, value in cls.__dict__.items(): + if isinstance(value, Field) and not name in cls_annotations: + raise TypeError(f'{name!r} is a field but has no type annotation') + + # Check rules that apply if we are derived from any dataclasses. + if has_dataclass_bases: + # Raise an exception if any of our bases are frozen, but we're not. + if any_frozen_base and not frozen: + raise TypeError('cannot inherit non-frozen dataclass from a ' + 'frozen one') + + # Raise an exception if we're frozen, but none of our bases are. + if not any_frozen_base and frozen: + raise TypeError('cannot inherit frozen dataclass from a ' + 'non-frozen one') + + # Remember all of the fields on our class (including bases). This + # also marks this class as being a dataclass. + setattr(cls, _FIELDS, fields) + + # Was this class defined with an explicit __hash__? Note that if + # __eq__ is defined in this class, then python will automatically + # set __hash__ to None. This is a heuristic, as it's possible + # that such a __hash__ == None was not auto-generated, but it + # close enough. + class_hash = cls.__dict__.get('__hash__', MISSING) + has_explicit_hash = not (class_hash is MISSING or (class_hash is None and '__eq__' in cls.__dict__)) + + # If we're generating ordering methods, we must be generating the + # eq methods. + if order and not eq: + raise ValueError('eq must be true if order is true') + + if init: + # Does this class have a post-init function? + has_post_init = hasattr(cls, _POST_INIT_NAME) + + # Include InitVars and regular fields (so, not ClassVars). + flds = [f for f in fields.values() if f._field_type in (_FIELD, _FIELD_INITVAR)] + _set_new_attribute( + cls, '__init__', + _init_fn( + flds, frozen, has_post_init, + # The name to use for the "self" + # param in __init__. Use "self" + # if possible. + '__dataclass_self__' if 'self' in fields else 'self', + ) + ) + + # Get the fields as a list, and include only real fields. This is + # used in all of the following methods. + field_list = [f for f in fields.values() if f._field_type is _FIELD] + + if repr: + flds = [f for f in field_list if f.repr] + _set_new_attribute(cls, '__repr__', _repr_fn(flds)) + + if eq: + # Create _eq__ method. There's no need for a __ne__ method, + # since python will call __eq__ and negate it. + flds = [f for f in field_list if f.compare] + self_tuple = _tuple_str('self', flds) + other_tuple = _tuple_str('other', flds) + _set_new_attribute(cls, '__eq__', _cmp_fn('__eq__', '==', self_tuple, other_tuple)) + + if order: + # Create and set the ordering methods. + flds = [f for f in field_list if f.compare] + self_tuple = _tuple_str('self', flds) + other_tuple = _tuple_str('other', flds) + for name, op in [('__lt__', '<'), ('__le__', '<='), ('__gt__', '>'), ('__ge__', '>='), ]: + if _set_new_attribute(cls, name, _cmp_fn(name, op, self_tuple, other_tuple)): + raise TypeError( + f'Cannot overwrite attribute {name} ' + f'in class {cls.__name__}. Consider using ' + 'functools.total_ordering' + ) + + if frozen: + for fn in _frozen_get_del_attr(cls, field_list): + if _set_new_attribute(cls, fn.__name__, fn): + raise TypeError(f'Cannot overwrite attribute {fn.__name__} ' + f'in class {cls.__name__}') + + # Decide if/how we're going to create a hash function. + hash_action = _hash_action[bool(unsafe_hash), bool(eq), bool(frozen), has_explicit_hash] + if hash_action: + # No need to call _set_new_attribute here, since by the time + # we're here the overwriting is unconditional. + cls.__hash__ = hash_action(cls, field_list) + + if not getattr(cls, '__doc__'): + # Create a class doc-string. + cls.__doc__ = (cls.__name__ + str(inspect.signature(cls)).replace(' -> None', '')) + + return cls # _cls should never be specified by keyword, so start it with an # underscore. The presence of _cls is used to detect if this # decorator is being called with parameters or not. -def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False, - unsafe_hash=False, frozen=False): - """Returns the same class as was passed in, with dunder methods +def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False): + """Returns the same class as was passed in, with dunder methods added based on the fields defined in the class. Examines PEP 526 __annotations__ to determine fields. @@ -945,50 +912,49 @@ def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False, __hash__() method function is added. If frozen is true, fields may not be assigned to after instance creation. """ + def wrap(cls): + return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) - def wrap(cls): - return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen) - - # See if we're being called as @dataclass or @dataclass(). - if _cls is None: - # We're called with parens. - return wrap + # See if we're being called as @dataclass or @dataclass(). + if _cls is None: + # We're called with parens. + return wrap - # We're called as @dataclass without parens. - return wrap(_cls) + # We're called as @dataclass without parens. + return wrap(_cls) def fields(class_or_instance): - """Return a tuple describing the fields of this dataclass. + """Return a tuple describing the fields of this dataclass. Accepts a dataclass or an instance of one. Tuple elements are of type Field. """ - # Might it be worth caching this, per class? - try: - fields = getattr(class_or_instance, _FIELDS) - except AttributeError: - raise TypeError('must be called with a dataclass type or instance') + # Might it be worth caching this, per class? + try: + fields = getattr(class_or_instance, _FIELDS) + except AttributeError: + raise TypeError('must be called with a dataclass type or instance') - # Exclude pseudo-fields. Note that fields is sorted by insertion - # order, so the order of the tuple is as the fields were defined. - return tuple(f for f in fields.values() if f._field_type is _FIELD) + # Exclude pseudo-fields. Note that fields is sorted by insertion + # order, so the order of the tuple is as the fields were defined. + return tuple(f for f in fields.values() if f._field_type is _FIELD) def _is_dataclass_instance(obj): - """Returns True if obj is an instance of a dataclass.""" - return not isinstance(obj, type) and hasattr(obj, _FIELDS) + """Returns True if obj is an instance of a dataclass.""" + return not isinstance(obj, type) and hasattr(obj, _FIELDS) def is_dataclass(obj): - """Returns True if obj is a dataclass or an instance of a + """Returns True if obj is a dataclass or an instance of a dataclass.""" - return hasattr(obj, _FIELDS) + return hasattr(obj, _FIELDS) def asdict(obj, *, dict_factory=dict): - """Return the fields of a dataclass instance as a new dictionary mapping + """Return the fields of a dataclass instance as a new dictionary mapping field names to field values. Example usage: @@ -1006,29 +972,28 @@ def asdict(obj, *, dict_factory=dict): dataclass instances. This will also look into built-in containers: tuples, lists, and dicts. """ - if not _is_dataclass_instance(obj): - raise TypeError("asdict() should be called on dataclass instances") - return _asdict_inner(obj, dict_factory) + if not _is_dataclass_instance(obj): + raise TypeError("asdict() should be called on dataclass instances") + return _asdict_inner(obj, dict_factory) def _asdict_inner(obj, dict_factory): - if _is_dataclass_instance(obj): - result = [] - for f in fields(obj): - value = _asdict_inner(getattr(obj, f.name), dict_factory) - result.append((f.name, value)) - return dict_factory(result) - elif isinstance(obj, (list, tuple)): - return type(obj)(_asdict_inner(v, dict_factory) for v in obj) - elif isinstance(obj, dict): - return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) - for k, v in obj.items()) - else: - return copy.deepcopy(obj) + if _is_dataclass_instance(obj): + result = [] + for f in fields(obj): + value = _asdict_inner(getattr(obj, f.name), dict_factory) + result.append((f.name, value)) + return dict_factory(result) + elif isinstance(obj, (list, tuple)): + return type(obj)(_asdict_inner(v, dict_factory) for v in obj) + elif isinstance(obj, dict): + return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) for k, v in obj.items()) + else: + return copy.deepcopy(obj) def astuple(obj, *, tuple_factory=tuple): - """Return the fields of a dataclass instance as a new tuple of field values. + """Return the fields of a dataclass instance as a new tuple of field values. Example usage:: @@ -1046,31 +1011,31 @@ def astuple(obj, *, tuple_factory=tuple): tuples, lists, and dicts. """ - if not _is_dataclass_instance(obj): - raise TypeError("astuple() should be called on dataclass instances") - return _astuple_inner(obj, tuple_factory) + if not _is_dataclass_instance(obj): + raise TypeError("astuple() should be called on dataclass instances") + return _astuple_inner(obj, tuple_factory) def _astuple_inner(obj, tuple_factory): - if _is_dataclass_instance(obj): - result = [] - for f in fields(obj): - value = _astuple_inner(getattr(obj, f.name), tuple_factory) - result.append(value) - return tuple_factory(result) - elif isinstance(obj, (list, tuple)): - return type(obj)(_astuple_inner(v, tuple_factory) for v in obj) - elif isinstance(obj, dict): - return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) - for k, v in obj.items()) - else: - return copy.deepcopy(obj) - - -def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, - repr=True, eq=True, order=False, unsafe_hash=False, - frozen=False): - """Return a new dynamically created dataclass. + if _is_dataclass_instance(obj): + result = [] + for f in fields(obj): + value = _astuple_inner(getattr(obj, f.name), tuple_factory) + result.append(value) + return tuple_factory(result) + elif isinstance(obj, (list, tuple)): + return type(obj)(_astuple_inner(v, tuple_factory) for v in obj) + elif isinstance(obj, dict): + return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) for k, v in obj.items()) + else: + return copy.deepcopy(obj) + + +def make_dataclass( + cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, + frozen=False +): + """Return a new dynamically created dataclass. The dataclass name will be 'cls_name'. 'fields' is an iterable of either (name), (name, type) or (name, type, Field) objects. If type is @@ -1093,48 +1058,47 @@ def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, dataclass(). """ - if namespace is None: - namespace = {} - else: - # Copy namespace since we're going to mutate it. - namespace = namespace.copy() - - # While we're looking through the field names, validate that they - # are identifiers, are not keywords, and not duplicates. - seen = set() - anns = {} - for item in fields: - if isinstance(item, str): - name = item - tp = 'typing.Any' - elif len(item) == 2: - name, tp, = item - elif len(item) == 3: - name, tp, spec = item - namespace[name] = spec - else: - raise TypeError(f'Invalid field: {item!r}') - - if not isinstance(name, str) or not name.isidentifier(): - raise TypeError(f'Field names must be valid identifers: {name!r}') - if keyword.iskeyword(name): - raise TypeError(f'Field names must not be keywords: {name!r}') - if name in seen: - raise TypeError(f'Field name duplicated: {name!r}') - - seen.add(name) - anns[name] = tp - - namespace['__annotations__'] = anns - # We use `types.new_class()` instead of simply `type()` to allow dynamic creation - # of generic dataclassses. - cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace)) - return dataclass(cls, init=init, repr=repr, eq=eq, order=order, - unsafe_hash=unsafe_hash, frozen=frozen) + if namespace is None: + namespace = {} + else: + # Copy namespace since we're going to mutate it. + namespace = namespace.copy() + + # While we're looking through the field names, validate that they + # are identifiers, are not keywords, and not duplicates. + seen = set() + anns = {} + for item in fields: + if isinstance(item, str): + name = item + tp = 'typing.Any' + elif len(item) == 2: + name, tp, = item + elif len(item) == 3: + name, tp, spec = item + namespace[name] = spec + else: + raise TypeError(f'Invalid field: {item!r}') + + if not isinstance(name, str) or not name.isidentifier(): + raise TypeError(f'Field names must be valid identifers: {name!r}') + if keyword.iskeyword(name): + raise TypeError(f'Field names must not be keywords: {name!r}') + if name in seen: + raise TypeError(f'Field name duplicated: {name!r}') + + seen.add(name) + anns[name] = tp + + namespace['__annotations__'] = anns + # We use `types.new_class()` instead of simply `type()` to allow dynamic creation + # of generic dataclassses. + cls = types.new_class(cls_name, bases, {}, lambda ns: ns.update(namespace)) + return dataclass(cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen) def replace(obj, **changes): - """Return a new object replacing specified fields with new values. + """Return a new object replacing specified fields with new values. This is especially useful for frozen classes. Example usage: @@ -1148,37 +1112,39 @@ def replace(obj, **changes): assert c1.x == 3 and c1.y == 2 """ - # We're going to mutate 'changes', but that's okay because it's a - # new dict, even if called with 'replace(obj, **my_changes)'. - - if not _is_dataclass_instance(obj): - raise TypeError("replace() should be called on dataclass instances") - - # It's an error to have init=False fields in 'changes'. - # If a field is not in 'changes', read its value from the provided obj. - - for f in getattr(obj, _FIELDS).values(): - # Only consider normal fields or InitVars. - if f._field_type is _FIELD_CLASSVAR: - continue - - if not f.init: - # Error if this field is specified in changes. - if f.name in changes: - raise ValueError(f'field {f.name} is declared with ' - 'init=False, it cannot be specified with ' - 'replace()') - continue - - if f.name not in changes: - if f._field_type is _FIELD_INITVAR: - raise ValueError(f"InitVar {f.name!r} " - 'must be specified with replace()') - changes[f.name] = getattr(obj, f.name) - - # Create the new object, which calls __init__() and - # __post_init__() (if defined), using all of the init fields we've - # added and/or left in 'changes'. If there are values supplied in - # changes that aren't fields, this will correctly raise a - # TypeError. - return obj.__class__(**changes) + # We're going to mutate 'changes', but that's okay because it's a + # new dict, even if called with 'replace(obj, **my_changes)'. + + if not _is_dataclass_instance(obj): + raise TypeError("replace() should be called on dataclass instances") + + # It's an error to have init=False fields in 'changes'. + # If a field is not in 'changes', read its value from the provided obj. + + for f in getattr(obj, _FIELDS).values(): + # Only consider normal fields or InitVars. + if f._field_type is _FIELD_CLASSVAR: + continue + + if not f.init: + # Error if this field is specified in changes. + if f.name in changes: + raise ValueError( + f'field {f.name} is declared with ' + 'init=False, it cannot be specified with ' + 'replace()' + ) + continue + + if f.name not in changes: + if f._field_type is _FIELD_INITVAR: + raise ValueError(f"InitVar {f.name!r} " + 'must be specified with replace()') + changes[f.name] = getattr(obj, f.name) + + # Create the new object, which calls __init__() and + # __post_init__() (if defined), using all of the init fields we've + # added and/or left in 'changes'. If there are values supplied in + # changes that aren't fields, this will correctly raise a + # TypeError. + return obj.__class__(**changes) diff --git a/python/datarender.py b/python/datarender.py index b5b21073..88f9d6d1 100644 --- a/python/datarender.py +++ b/python/datarender.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - import traceback import ctypes @@ -49,6 +48,7 @@ class TypeContext: """The offset into the given type object""" return self._offset + class DataRenderer: """ DataRenderer objects tell the Linear View how to render specific types. @@ -95,8 +95,10 @@ class DataRenderer: @staticmethod def is_type_of_struct_name(t, name, context): - return (t.type_class == enums.TypeClass.StructureTypeClass and len(context) > 0 - and isinstance(context[-1].type, types.NamedTypeReferenceType) and context[-1].type.name == name) + return ( + t.type_class == enums.TypeClass.StructureTypeClass and len(context) > 0 + and isinstance(context[-1].type, types.NamedTypeReferenceType) and context[-1].type.name == name + ) def register_type_specific(self): core.BNRegisterTypeSpecificDataRenderer(core.BNGetDataRendererContainer(), self.handle) @@ -119,7 +121,9 @@ class DataRenderer: type = types.Type.create(handle=core.BNNewTypeReference(type)) pycontext = [] for i in range(0, ctxCount): - pycontext.append(TypeContext(types.Type.create(core.BNNewTypeReference(context[i].type)), context[i].offset)) + pycontext.append( + TypeContext(types.Type.create(core.BNNewTypeReference(context[i].type)), context[i].offset) + ) return self.perform_is_valid_for_data(ctxt, view, addr, type, pycontext) except: log_error(traceback.format_exc()) @@ -134,7 +138,9 @@ class DataRenderer: prefixTokens = function.InstructionTextToken._from_core_struct(prefix, prefixCount) pycontext = [] for i in range(ctxCount): - pycontext.append(TypeContext(types.Type.create(core.BNNewTypeReference(typeCtx[i].type)), typeCtx[i].offset)) + pycontext.append( + TypeContext(types.Type.create(core.BNNewTypeReference(typeCtx[i].type)), typeCtx[i].offset) + ) result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext) @@ -143,7 +149,8 @@ class DataRenderer: for i in range(len(result)): line = result[i] color = line.highlight - if not isinstance(color, enums.HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): + if not isinstance(color, + enums.HighlightStandardColor) and not isinstance(color, highlight.HighlightColor): raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor") if isinstance(color, enums.HighlightStandardColor): color = highlight.HighlightColor(color) diff --git a/python/debuginfo.py b/python/debuginfo.py index ba96c27f..a48182e6 100644 --- a/python/debuginfo.py +++ b/python/debuginfo.py @@ -33,7 +33,6 @@ from .log import log_error from . import binaryview from . import filemetadata - _debug_info_parsers = {} @@ -98,18 +97,21 @@ class _DebugInfoParserMetaClass(type): @staticmethod def _is_valid(view: core.BNBinaryView, callback: Callable[['binaryview.BinaryView'], bool]) -> bool: try: - file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) return callback(view_obj) except: log_error(traceback.format_exc()) return False @staticmethod - def _parse_info(debug_info: core.BNDebugInfo, view: core.BNBinaryView, callback: Callable[["DebugInfo", 'binaryview.BinaryView'], None]) -> None: + def _parse_info( + debug_info: core.BNDebugInfo, view: core.BNBinaryView, + callback: Callable[["DebugInfo", 'binaryview.BinaryView'], None] + ) -> None: try: - file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) - view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) parser_ref = core.BNNewDebugInfoReference(debug_info) assert parser_ref is not None, "core.BNNewDebugInfoReference returned None" callback(DebugInfo(parser_ref), view_obj) @@ -117,12 +119,19 @@ class _DebugInfoParserMetaClass(type): log_error(traceback.format_exc()) @classmethod - def register(cls, name: str, is_valid: Callable[['binaryview.BinaryView'], bool], parse_info: Callable[["DebugInfo", 'binaryview.BinaryView'], None]) -> "DebugInfoParser": + def register( + cls, name: str, is_valid: Callable[['binaryview.BinaryView'], bool], + parse_info: Callable[["DebugInfo", 'binaryview.BinaryView'], None] + ) -> "DebugInfoParser": """Registers a DebugInfoParser. See ``debuginfo.DebugInfoParser`` for more details.""" binaryninja._init_plugins() - is_valid_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView))(lambda ctxt, view: cls._is_valid(view, is_valid)) - parse_info_cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNDebugInfo), ctypes.POINTER(core.BNBinaryView))(lambda ctxt, debug_info, view: cls._parse_info(debug_info, view, parse_info)) + is_valid_cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.POINTER(core.BNBinaryView + ))(lambda ctxt, view: cls._is_valid(view, is_valid)) + parse_info_cb = ctypes.CFUNCTYPE( + None, ctypes.c_void_p, ctypes.POINTER(core.BNDebugInfo), ctypes.POINTER(core.BNBinaryView) + )(lambda ctxt, debug_info, view: cls._parse_info(debug_info, view, parse_info)) # Don't let our callbacks get garbage collected global _debug_info_parsers @@ -231,15 +240,15 @@ class DebugFunctionInfo(object): Functions will not be created if an address is not provided, but will be able to be queried from debug info for later user analysis. """ - short_name:Optional[str] = None - full_name:Optional[str] = None - raw_name:Optional[str] = None - address:Optional[int] = None - return_type:Optional[_types.Type] = None - parameters:Optional[List[Tuple[str, _types.Type]]] = None - variable_parameters:Optional[bool] = None - calling_convention:Optional[callingconvention.CallingConvention] = None - platform:Optional['_platform.Platform'] = None + short_name: Optional[str] = None + full_name: Optional[str] = None + raw_name: Optional[str] = None + address: Optional[int] = None + return_type: Optional[_types.Type] = None + parameters: Optional[List[Tuple[str, _types.Type]]] = None + variable_parameters: Optional[bool] = None + calling_convention: Optional[callingconvention.CallingConvention] = None + platform: Optional['_platform.Platform'] = None def __repr__(self) -> str: suffix = f"@{self.address:#x}>" if self.address != 0 else ">" @@ -301,7 +310,10 @@ class DebugInfo(object): parameters: List[Tuple[str, _types.Type]] = [] for j in range(functions[i].parameterCount): - parameters.append((functions[i].parameterNames[j], _types.Type(core.BNNewTypeReference(functions[i].parameterTypes[j])))) + parameters.append(( + functions[i].parameterNames[j], + _types.Type(core.BNNewTypeReference(functions[i].parameterTypes[j])) + )) if functions[i].returnType: return_type = _types.Type(core.BNNewTypeReference(functions[i].returnType)) @@ -309,7 +321,9 @@ class DebugInfo(object): return_type = None if functions[i].callingConvention: - calling_convention = callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(functions[i].callingConvention)) + calling_convention = callingconvention.CallingConvention( + handle=core.BNNewCallingConventionReference(functions[i].callingConvention) + ) else: calling_convention = None @@ -319,15 +333,8 @@ class DebugInfo(object): func_platform = None yield DebugFunctionInfo( - functions[i].address, - functions[i].shortName, - functions[i].fullName, - functions[i].rawName, - return_type, - parameters, - functions[i].variableParameters, - calling_convention, - func_platform + functions[i].address, functions[i].shortName, functions[i].fullName, functions[i].rawName, + return_type, parameters, functions[i].variableParameters, calling_convention, func_platform ) finally: core.BNFreeDebugFunctions(functions, count.value) @@ -345,10 +352,11 @@ class DebugInfo(object): try: for i in range(0, count.value): yield binaryview.DataVariableAndName( - data_variables[i].address, - _types.Type(core.BNNewTypeReference(data_variables[i].type), confidence=data_variables[i].typeConfidence), - data_variables[i].name, - data_variables[i].autoDiscovered) + data_variables[i].address, + _types.Type( + core.BNNewTypeReference(data_variables[i].type), confidence=data_variables[i].typeConfidence + ), data_variables[i].name, data_variables[i].autoDiscovered + ) finally: core.BNFreeDataVariablesAndName(data_variables, count.value) @@ -357,7 +365,7 @@ class DebugInfo(object): """A generator of all data variables provided by DebugInfoParsers""" return self.data_variables_from_parser() - def add_type(self, name: str, new_type:'_types.Type') -> bool: + def add_type(self, name: str, new_type: '_types.Type') -> bool: """Adds a type scoped under the current parser's name to the debug info""" if isinstance(new_type, _types.Type): return core.BNAddDebugType(self.handle, name, new_type.handle) @@ -406,8 +414,12 @@ class DebugInfo(object): func_info.parameterTypes = None func_info.parameterCount = parameter_count else: - func_info.parameterNames = (ctypes.c_char_p * parameter_count)(*map(lambda pair: binaryninja.cstr(pair[0]), new_func.parameters)) # type: ignore - func_info.parameterTypes = (ctypes.POINTER(core.BNType) * parameter_count)(*map(lambda pair: pair[1].handle, new_func.parameters)) # type: ignore + func_info.parameterNames = (ctypes.c_char_p * parameter_count)( + *map(lambda pair: binaryninja.cstr(pair[0]), new_func.parameters) + ) # type: ignore + func_info.parameterTypes = (ctypes.POINTER(core.BNType) * parameter_count)( + *map(lambda pair: pair[1].handle, new_func.parameters) + ) # type: ignore func_info.parameterCount = parameter_count return core.BNAddDebugFunction(self.handle, func_info) diff --git a/python/decorators.py b/python/decorators.py index fcd3a8be..e02829f8 100644 --- a/python/decorators.py +++ b/python/decorators.py @@ -10,4 +10,3 @@ def passive(cls): cls.__doc__ = passive_note return cls - diff --git a/python/demangle.py b/python/demangle.py index 3f22d294..6e9185ec 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -44,7 +44,7 @@ def get_qualified_name(names): return "::".join(names) -def demangle_ms(arch, mangled_name, options = False): +def demangle_ms(arch, mangled_name, options=False): """ ``demangle_ms`` demangles a mangled Microsoft Visual Studio C++ name to a Type object. @@ -64,9 +64,19 @@ def demangle_ms(arch, mangled_name, options = False): outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] - if (isinstance(options, binaryview.BinaryView) and core.BNDemangleMSWithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ - (isinstance(options, bool) and core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ - (options is None and core.BNDemangleMSWithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None)): + if ( + isinstance(options, binaryview.BinaryView) and core.BNDemangleMSWithOptions( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options + ) + ) or ( + isinstance(options, bool) and core.BNDemangleMS( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options + ) + ) or ( + options is None and core.BNDemangleMSWithOptions( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None + ) + ): for i in range(outSize.value): names.append(outName[i].decode('utf8')) # type: ignore core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) @@ -74,7 +84,7 @@ def demangle_ms(arch, mangled_name, options = False): return (None, mangled_name) -def demangle_gnu3(arch, mangled_name, options = None): +def demangle_gnu3(arch, mangled_name, options=None): """ ``demangle_gnu3`` demangles a mangled name to a Type object. @@ -89,9 +99,19 @@ def demangle_gnu3(arch, mangled_name, options = None): outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() names = [] - if (isinstance(options, binaryview.BinaryView) and core.BNDemangleGNU3WithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ - (isinstance(options, bool) and core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options)) or \ - (options is None and core.BNDemangleGNU3WithOptions(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None)): + if ( + isinstance(options, binaryview.BinaryView) and core.BNDemangleGNU3WithOptions( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options + ) + ) or ( + isinstance(options, bool) and core.BNDemangleGNU3( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), options + ) + ) or ( + options is None and core.BNDemangleGNU3WithOptions( + arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize), None + ) + ): for i in range(outSize.value): names.append(outName[i].decode('utf8')) # type: ignore core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) @@ -125,7 +145,7 @@ def simplify_name_to_string(input_name): return result -def simplify_name_to_qualified_name(input_name, simplify = True): +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 @@ -158,5 +178,5 @@ def simplify_name_to_qualified_name(input_name, simplify = True): name_count = len(native_result) native_result = types.QualifiedName(native_result) - core.BNRustFreeStringArray(result, name_count+1) + core.BNRustFreeStringArray(result, name_count + 1) return native_result diff --git a/python/downloadprovider.py b/python/downloadprovider.py index 793dc298..ed61136c 100644 --- a/python/downloadprovider.py +++ b/python/downloadprovider.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - import abc import ctypes from json import dumps @@ -52,7 +51,7 @@ class DownloadInstance(object): self.headers = headers self.content = content - def __init__(self, provider, handle = None): + def __init__(self, provider, handle=None): if handle is None: self._cb = core.BNDownloadInstanceCallbacks() self._cb.context = 0 @@ -88,7 +87,8 @@ class DownloadInstance(object): def _perform_custom_request(self, ctxt, method, url, header_count, header_keys, header_values, response): # Cast response to an array of length 1 so ctypes can write to the pointer # out_response = ((BNDownloadInstanceResponse*)[1])response - out_response = (ctypes.POINTER(core.BNDownloadInstanceResponse) * 1).from_address(ctypes.addressof(response.contents)) # type: ignore + out_response = (ctypes.POINTER(core.BNDownloadInstanceResponse) + * 1).from_address(ctypes.addressof(response.contents)) # type: ignore try: # Extract headers keys_ptr = ctypes.cast(header_keys, ctypes.POINTER(ctypes.c_char_p)) @@ -103,7 +103,9 @@ class DownloadInstance(object): def data_generator(): while True: read_buffer = ctypes.create_string_buffer(0x1000) - read_len = core.BNReadDataForDownloadInstance(self.handle, ctypes.cast(read_buffer, ctypes.POINTER(ctypes.c_uint8)), 0x1000) + read_len = core.BNReadDataForDownloadInstance( + self.handle, ctypes.cast(read_buffer, ctypes.POINTER(ctypes.c_uint8)), 0x1000 + ) if read_len == 0: break if read_len < 0: @@ -203,7 +205,7 @@ class DownloadInstance(object): if "Content-Type" not in headers: headers["Content-Type"] = "application/x-www-form-urlencoded" else: - assert(type(data) == bytes) + assert (type(data) == bytes) self._data = data if len(data) > 0 and "Content-Length" not in headers: @@ -226,7 +228,9 @@ class DownloadInstance(object): header_values[i] = to_bytes(value) response = ctypes.POINTER(core.BNDownloadInstanceResponse)() - result = core.BNPerformCustomRequest(self.handle, method, url, len(headers), header_keys, header_values, response, callbacks) + result = core.BNPerformCustomRequest( + self.handle, method, url, len(headers), header_keys, header_values, response, callbacks + ) if result != 0: return None @@ -246,6 +250,7 @@ class DownloadInstance(object): def put(self, url, headers=None, data=None, json=None): return self.request("POST", url, headers, data, json) + class _DownloadProviderMetaclass(type): def __iter__(self): binaryninja._init_plugins() @@ -270,7 +275,7 @@ class DownloadProvider(metaclass=_DownloadProviderMetaclass): instance_class = None _registered_providers = [] - def __init__(self, handle = None): + def __init__(self, handle=None): if handle is not None: self.handle = core.handle_of_type(handle, core.BNDownloadProvider) self.__dict__["name"] = core.BNGetDownloadProviderName(handle) @@ -299,7 +304,7 @@ class DownloadProvider(metaclass=_DownloadProviderMetaclass): result = core.BNCreateDownloadProviderInstance(self.handle) if result is None: return None - return DownloadInstance(self, handle = result) + return DownloadInstance(self, handle=result) _loaded = False @@ -398,7 +403,10 @@ try: if b"Content-Length" in headers: del headers[b"Content-Length"] - r = requests.request(method.decode('utf8'), url.decode('utf8'), headers=headers, data=data_generator, proxies=proxies, stream=True) + r = requests.request( + method.decode('utf8'), url.decode('utf8'), headers=headers, data=data_generator, proxies=proxies, + stream=True + ) total_size = 0 for (key, value) in r.headers.items(): @@ -465,7 +473,9 @@ if not _loaded and (sys.platform != "win32") and (sys.version_info >= (2, 7, 9)) core.BNSetErrorForDownloadInstance(self.handle, "Bytes written mismatch!") return -1 bytes_sent = bytes_sent + bytes_wrote - continue_download = core.BNNotifyProgressForDownloadInstance(self.handle, bytes_sent, total_size) + continue_download = core.BNNotifyProgressForDownloadInstance( + self.handle, bytes_sent, total_size + ) if continue_download is False: core.BNSetErrorForDownloadInstance(self.handle, "Download aborted!") return -1 @@ -490,7 +500,6 @@ if not _loaded and (sys.platform != "win32") and (sys.version_info >= (2, 7, 9)) urllib2 (python2) does not have a parameter for custom request methods So this is a shim class to deal with that """ - def __init__(self, *args, **kwargs): if "method" in kwargs: self._method = kwargs["method"] @@ -518,7 +527,9 @@ if not _loaded and (sys.platform != "win32") and (sys.version_info >= (2, 7, 9)) if b"Content-Length" in headers: del headers[b"Content-Length"] - req = PythonDownloadInstance.CustomRequest(url.decode('utf8'), data=data_generator, headers=headers, method=method.decode('utf8')) + req = PythonDownloadInstance.CustomRequest( + url.decode('utf8'), data=data_generator, headers=headers, method=method.decode('utf8') + ) result = urlopen(req) except HTTPError as he: result = he @@ -562,8 +573,12 @@ if not _loaded: log_error("Please install the requests package into the selected Python environment:") log_error(" python -m pip install requests") else: - log_error("On Python versions below 2.7.9, the pip requests[security] package is required for network connectivity!") - log_error("On an Ubuntu 14.04 install, the following three commands are sufficient to enable networking for the current user:") + log_error( + "On Python versions below 2.7.9, the pip requests[security] package is required for network connectivity!" + ) + log_error( + "On an Ubuntu 14.04 install, the following three commands are sufficient to enable networking for the current user:" + ) log_error(" sudo apt install python-pip") log_error(" python -m pip install pip --upgrade --user") log_error(" python -m pip install requests[security] --upgrade --user") diff --git a/python/enterprise.py b/python/enterprise.py index 18062153..e3c0e26c 100644 --- a/python/enterprise.py +++ b/python/enterprise.py @@ -271,7 +271,6 @@ class LicenseCheckout: # License is released at end of scope """ - def __init__(self, duration=900, cache=False): self.desired_duration = duration self.desired_cache = cache @@ -284,8 +283,9 @@ class LicenseCheckout: connect() if not is_authenticated(): raise RuntimeError( - "Could not checkout a license: Not authenticated. " - "Please use binaryninja.enterprise.authenticate_with_credentials or authenticate_with_method first!") + "Could not checkout a license: Not authenticated. " + "Please use binaryninja.enterprise.authenticate_with_credentials or authenticate_with_method first!" + ) acquire_license(self.desired_duration, self.desired_cache) def __exit__(self, exc_type, exc_val, exc_tb): diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py index 940aff8b..5f2eeba0 100644 --- a/python/examples/angr_plugin.py +++ b/python/examples/angr_plugin.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - # This plugin assumes angr is already installed and available on the system. See the angr documentation # for information about installing angr. It should be installed using the virtualenv method. # @@ -72,7 +71,7 @@ class Solver(BackgroundTaskThread): def run(self): # Create an angr project and an explorer with the user's settings p = angr.Project(self.binary.name) - e = p.surveyors.Explorer(find = self.find, avoid = self.avoid) + e = p.surveyors.Explorer(find=self.find, avoid=self.avoid) # Solve loop while not e.done: @@ -98,7 +97,7 @@ class Solver(BackgroundTaskThread): text_report = "Found %d path%s.\n\n" % (len(e.found), "s" if len(e.found) != 1 else "") i = 1 for f in e.found: - text_report += "Path %d\n" % i + "=" * 10 + "\n" + text_report += "Path %d\n"%i + "="*10 + "\n" text_report += "stdin:\n" + escaped_output(f.state.posix.dumps(0)) + "\n\n" text_report += "stdout:\n" + escaped_output(f.state.posix.dumps(1)) + "\n\n" text_report += "stderr:\n" + escaped_output(f.state.posix.dumps(2)) + "\n\n" @@ -115,7 +114,7 @@ def find_instr(bv, addr): # Highlight the instruction in green blocks = bv.get_basic_blocks_at(addr) for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128)) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha=128)) block.function.set_auto_instr_highlight(addr, HighlightStandardColor.GreenHighlightColor) # Add the instruction to the list associated with the current view @@ -126,7 +125,7 @@ def avoid_instr(bv, addr): # Highlight the instruction in red blocks = bv.get_basic_blocks_at(addr) for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128)) + block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha=128)) block.function.set_auto_instr_highlight(addr, HighlightStandardColor.RedHighlightColor) # Add the instruction to the list associated with the current view @@ -135,9 +134,11 @@ def avoid_instr(bv, addr): def solve(bv): if len(bv.session_data.angr_find) == 0: - show_message_box("Angr Solve", "You have not specified a goal instruction.\n\n" + - "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + - "continue.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon) + show_message_box( + "Angr Solve", "You have not specified a goal instruction.\n\n" + + "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + "continue.", + MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon + ) return # Start a solver thread for the path associated with the view @@ -146,8 +147,10 @@ def solve(bv): # Register commands for the user to interact with the plugin -PluginCommand.register_for_address("Find Path to This Instruction", - "When solving, find a path that gets to this instruction", find_instr) -PluginCommand.register_for_address("Avoid This Instruction", - "When solving, avoid paths that reach this instruction", avoid_instr) +PluginCommand.register_for_address( + "Find Path to This Instruction", "When solving, find a path that gets to this instruction", find_instr +) +PluginCommand.register_for_address( + "Avoid This Instruction", "When solving, avoid paths that reach this instruction", avoid_instr +) PluginCommand.register("Solve With Angr", "Attempt to solve for a path that satisfies the constraints given", solve) diff --git a/python/examples/arch_hook.py b/python/examples/arch_hook.py index 452bd2b6..a6e280cc 100644 --- a/python/examples/arch_hook.py +++ b/python/examples/arch_hook.py @@ -1,16 +1,17 @@ from binaryninja.architecture import Architecture, ArchitectureHook + class X86ReturnHook(ArchitectureHook): - def get_instruction_text(self, data, addr): - # Call the original implementation's method by calling the superclass - result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + def get_instruction_text(self, data, addr): + # Call the original implementation's method by calling the superclass + result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + + # Patch the name of the 'retn' instruction to 'ret' + if len(result) > 0 and result[0].text == 'retn': + result[0].text = 'ret' - # Patch the name of the 'retn' instruction to 'ret' - if len(result) > 0 and result[0].text == 'retn': - result[0].text = 'ret' + return result, length - return result, length # Install the hook by constructing it with the desired architecture to hook, then registering it X86ReturnHook(Architecture['x86']).register() - diff --git a/python/examples/asm_to_llil_view.py b/python/examples/asm_to_llil_view.py index 18c77547..3b7fb374 100644 --- a/python/examples/asm_to_llil_view.py +++ b/python/examples/asm_to_llil_view.py @@ -1,5 +1,5 @@ # Copyright (c) 2019-2022 Vector 35 Inc -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the @@ -103,13 +103,18 @@ class DisassemblyAndLowLevelILGraph(FlowGraph): for line in lines: if line.il_instruction is None: # For assembly lines, show address - line.tokens.insert(0, InstructionTextToken(InstructionTextTokenType.AddressDisplayToken, - "%.8x" % line.address, line.address)) + line.tokens.insert( + 0, InstructionTextToken(InstructionTextTokenType.AddressDisplayToken, "%.8x" % line.address, line.address) + ) line.tokens.insert(1, InstructionTextToken(InstructionTextTokenType.TextToken, " ")) else: # For IL lines, show IL instruction index - line.tokens.insert(0, InstructionTextToken(InstructionTextTokenType.AnnotationToken, - "%8s" % ("[%d]" % line.il_instruction.instr_index))) + line.tokens.insert( + 0, + InstructionTextToken( + InstructionTextTokenType.AnnotationToken, "%8s" % ("[%d]" % line.il_instruction.instr_index) + ) + ) line.tokens.insert(1, InstructionTextToken(InstructionTextTokenType.AnnotationToken, " => ")) nodes[block.start].lines = lines diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py index ab2ccfa5..20ff2b6b 100644 --- a/python/examples/breakpoint.py +++ b/python/examples/breakpoint.py @@ -18,7 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. - from binaryninja.plugin import PluginCommand from binaryninja.log import log_error @@ -29,12 +28,7 @@ def write_breakpoint(view, start, length): register_for_address register_for_function """ - bkpt_str = { - "x86": "int3", - "x86_64": "int3", - "armv7": "bkpt", - "aarch64": "brk #0", - "mips32": "break"} + bkpt_str = {"x86": "int3", "x86_64": "int3", "armv7": "bkpt", "aarch64": "brk #0", "mips32": "break"} if view.arch.name not in bkpt_str: log_error("Architecture %s not supported" % view.arch.name) diff --git a/python/examples/cli_dis.py b/python/examples/cli_dis.py index 8f863db3..cbd4b8f1 100755 --- a/python/examples/cli_dis.py +++ b/python/examples/cli_dis.py @@ -55,12 +55,12 @@ archName = sys.argv[1] bytesList = sys.argv[2:] # parse byte arguments -data = b''.join(list(map(lambda x: int(x,16).to_bytes(1,'big'), bytesList))) +data = b''.join(list(map(lambda x: int(x, 16).to_bytes(1, 'big'), bytesList))) # disassemble arch = binaryninja.Architecture[archName] toksAndLen = arch.get_instruction_text(data, 0) -if not toksAndLen or toksAndLen[1]==0: +if not toksAndLen or toksAndLen[1] == 0: print('disassembly failed') sys.exit(-1) @@ -68,4 +68,3 @@ if not toksAndLen or toksAndLen[1]==0: toks = toksAndLen[0] strs = map(lambda x: x.text, toks) print(GREEN, ''.join(strs), NORMAL) - diff --git a/python/examples/cli_lift.py b/python/examples/cli_lift.py index b335a5e4..946f8c3a 100755 --- a/python/examples/cli_lift.py +++ b/python/examples/cli_lift.py @@ -34,16 +34,18 @@ from binaryninja import lowlevelil RED = '\x1B[31m' NORMAL = '\x1B[0m' + def traverse_IL(il, indent): if isinstance(il, lowlevelil.LowLevelILInstruction): print('\t'*indent + il.operation.name) for o in il.operands: - traverse_IL(o, indent+1) + traverse_IL(o, indent + 1) else: print('\t'*indent + str(il)) + if __name__ == '__main__': if not sys.argv[2:]: @@ -63,7 +65,7 @@ if __name__ == '__main__': bytesList = sys.argv[2:] # parse byte arguments - data = b''.join(list(map(lambda x: int(x,16).to_bytes(1,'big'), bytesList))) + data = b''.join(list(map(lambda x: int(x, 16).to_bytes(1, 'big'), bytesList))) plat = binaryninja.Platform[platName] bv = binaryview.BinaryView.new(data) @@ -71,13 +73,13 @@ if __name__ == '__main__': bv.add_function(0, plat=plat) -# print('print all the functions, their basic blocks, and their mc instructions') -# for func in bv.functions: -# print(repr(func)) -# for block in func: -# print("\t{0}".format(block)) -# for insn in block: -# print("\t\t{0}".format(insn)) + # print('print all the functions, their basic blocks, and their mc instructions') + # for func in bv.functions: + # print(repr(func)) + # for block in func: + # print("\t{0}".format(block)) + # for insn in block: + # print("\t\t{0}".format(insn)) print(RED) for func in bv.functions: @@ -87,4 +89,3 @@ if __name__ == '__main__': for insn in block: traverse_IL(insn, 0) print(NORMAL) - diff --git a/python/examples/debug_info.py b/python/examples/debug_info.py index 8f379544..28175ba1 100755 --- a/python/examples/debug_info.py +++ b/python/examples/debug_info.py @@ -29,7 +29,6 @@ # bv.apply_debug_info(debug_info) # ``` - # The rest of this file serves as a test and example of implementing debug info parsers, and the resultant debug info. # # All that is required is to provide functions similar to "is_valid" and "parse_info" below, and call @@ -98,50 +97,56 @@ # } # ``` - import binaryninja as bn import os - filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_debug_info") - # Some setup code not just for informative printing - print = print if __name__ != "__main__": - print = bn.log_error + print = bn.log_error -def pretty_print_add_data_variable(debug_info: bn.debuginfo.DebugInfo, address: int, t: bn.types.Type, name: str = None) -> None: - print(f" Adding data variable of type `{t}` at {hex(address)} : {debug_info.add_data_variable(address, t, name)}") +def pretty_print_add_data_variable( + debug_info: bn.debuginfo.DebugInfo, address: int, t: bn.types.Type, name: str = None +) -> None: + print(f" Adding data variable of type `{t}` at {hex(address)} : {debug_info.add_data_variable(address, t, name)}") -def pretty_print_add_function(debug_info: bn.debuginfo.DebugInfo, address: int, short_name: str = None, full_name: str = None, raw_name: str = None, return_type = None, parameters = None) -> None: - function_info = bn.debuginfo.DebugFunctionInfo(address, short_name, full_name, raw_name, return_type, parameters) - if parameters is not None: - print(f" Adding function `{return_type} {short_name}({', '.join(f'{t} {name}' for name, t in parameters)})` at {hex(address)} : {debug_info.add_function(function_info)}") - else: - print(f" Adding function `{return_type} {short_name}()` at {hex(address)} : {debug_info.add_function(function_info)}") +def pretty_print_add_function( + debug_info: bn.debuginfo.DebugInfo, address: int, short_name: str = None, full_name: str = None, raw_name: str = None, + return_type=None, parameters=None +) -> None: + function_info = bn.debuginfo.DebugFunctionInfo(address, short_name, full_name, raw_name, return_type, parameters) + if parameters is not None: + print( + f" Adding function `{return_type} {short_name}({', '.join(f'{t} {name}' for name, t in parameters)})` at {hex(address)} : {debug_info.add_function(function_info)}" + ) + else: + print( + f" Adding function `{return_type} {short_name}()` at {hex(address)} : {debug_info.add_function(function_info)}" + ) # The beginning of the actual debug info plugin def is_valid(bv: bn.binaryview.BinaryView): - sym = bv.get_symbol_by_raw_name("__elf_interp") - if sym is None: - return False - else: - var = bv.get_data_var_at(sym.address) - return b"test_debug_info_parsing" == bv.read(sym.address, var.type.width-1) + sym = bv.get_symbol_by_raw_name("__elf_interp") + if sym is None: + return False + else: + var = bv.get_data_var_at(sym.address) + return b"test_debug_info_parsing" == bv.read(sym.address, var.type.width - 1) def parse_info(debug_info: bn.debuginfo.DebugInfo, bv: bn.binaryview.BinaryView): - print("Adding types") - types = [] - for name, t in bv.parse_types_from_string(""" + print("Adding types") + types = [] + for name, t in bv.parse_types_from_string( + """ struct test_type_1 { int a; char b[4]; @@ -153,62 +158,81 @@ def parse_info(debug_info: bn.debuginfo.DebugInfo, bv: bn.binaryview.BinaryView) struct test_type_1 a; struct test_type_1* b; struct test_type_2* c; - };""").types.items(): - print(f" Adding type \"{name}\" `{t}` : {debug_info.add_type(str(name), t)}") - types.append(t) - - print("Adding data variables") - pretty_print_add_data_variable(debug_info, 0x4030, types[0], "test_var_1") - pretty_print_add_data_variable(debug_info, 0x4010, bn.types.Type.int(4, True), "test_var_2") - # Names are optional - pretty_print_add_data_variable(debug_info, 0x4014, bn.types.Type.int(4, True)) - - t = bn.types.Type.int(4, True) - t.const = True - pretty_print_add_data_variable(debug_info, 0x2004, t, "test_var_3") - - print("Adding functions") - char_star = bv.parse_type_string("char*")[0] - pretty_print_add_function(debug_info, 0x1129, "no_return_type_no_parameters", None, None, bn.types.Type.void(), None) - pretty_print_add_function(debug_info, 0x1134, "used_parameter", None, None, bn.types.Type.bool(), [("value", bn.types.Type.bool())]) - pretty_print_add_function(debug_info, 0x1155, "unused_parameters", None, None, bn.types.Type.int(4, True), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star)]) - pretty_print_add_function(debug_info, 0x1170, "used_and_unused_parameters_1", None, None, bn.types.Type.int(4, True), [("value_1", bn.types.Type.int(4, True)), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star), ("value_4", bn.types.Type.bool())]) - pretty_print_add_function(debug_info, 0x1191, "used_and_unused_parameters_2", None, None, bn.types.Type.int(1, False), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())]) - pretty_print_add_function(debug_info, 0x11c0, "local_parameters", None, None, bn.types.Type.void(), [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())]) + };""" + ).types.items(): + print(f" Adding type \"{name}\" `{t}` : {debug_info.add_type(str(name), t)}") + types.append(t) + + print("Adding data variables") + pretty_print_add_data_variable(debug_info, 0x4030, types[0], "test_var_1") + pretty_print_add_data_variable(debug_info, 0x4010, bn.types.Type.int(4, True), "test_var_2") + # Names are optional + pretty_print_add_data_variable(debug_info, 0x4014, bn.types.Type.int(4, True)) + + t = bn.types.Type.int(4, True) + t.const = True + pretty_print_add_data_variable(debug_info, 0x2004, t, "test_var_3") + + print("Adding functions") + char_star = bv.parse_type_string("char*")[0] + pretty_print_add_function(debug_info, 0x1129, "no_return_type_no_parameters", None, None, bn.types.Type.void(), None) + pretty_print_add_function( + debug_info, 0x1134, "used_parameter", None, None, bn.types.Type.bool(), [("value", bn.types.Type.bool())] + ) + pretty_print_add_function( + debug_info, 0x1155, "unused_parameters", None, None, bn.types.Type.int(4, True), + [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star)] + ) + pretty_print_add_function( + debug_info, 0x1170, "used_and_unused_parameters_1", None, None, bn.types.Type.int(4, True), + [("value_1", bn.types.Type.int(4, True)), ("value_2", bn.types.Type.int(4, True)), ("value_3", char_star), + ("value_4", bn.types.Type.bool())] + ) + pretty_print_add_function( + debug_info, 0x1191, "used_and_unused_parameters_2", None, None, bn.types.Type.int(1, False), + [("value_1", bn.types.Type.bool()), ("value_2", bn.types.Type.int(1, False)), ("value_3", char_star), + ("value_4", bn.types.Type.int(1, False)), ("value_5", bn.types.Type.char())] + ) + pretty_print_add_function( + debug_info, 0x11c0, "local_parameters", None, None, bn.types.Type.void(), [("value_1", bn.types.Type.bool()), + ("value_2", bn.types.Type.int(1, False)), + ("value_3", char_star), + ("value_4", bn.types.Type.int(1, False)), + ("value_5", bn.types.Type.char())] + ) parser = bn.debuginfo.DebugInfoParser.register("test debug info parser", is_valid, parse_info) print(f"Registered parser: {parser.name}") - # The above is all that is needed for a DebugInfo plugin # The below serves to test the correctness of (the Python bindings' implementation of) debug info parsers' functionality. - bn.debuginfo.DebugInfoParser.register("dummy extra debug parser 1", lambda bv: False, lambda di, bv: None) -bn.debuginfo.DebugInfoParser.register("dummy extra debug parser 2", lambda bv: bv.view_type != "Raw", lambda di, bv: None) +bn.debuginfo.DebugInfoParser.register( + "dummy extra debug parser 2", lambda bv: bv.view_type != "Raw", lambda di, bv: None +) # Test fetching parser list and fetching by name print(f"Availible parsers: {len(list(bn.debuginfo.DebugInfoParser))}") for p in bn.debuginfo.DebugInfoParser: - if p == parser: - print(f" {bn.debuginfo.DebugInfoParser[p.name].name} (the one we just registered)") - else: - print(f" {bn.debuginfo.DebugInfoParser[p.name].name}") + if p == parser: + print(f" {bn.debuginfo.DebugInfoParser[p.name].name} (the one we just registered)") + else: + print(f" {bn.debuginfo.DebugInfoParser[p.name].name}") # Test calling our `is_valid` callback bv = bn.open_view(filename, options={"analysis.experimental.parseDebugInfo": False}) if parser.is_valid_for_view(bv): - print("Parser is valid") + print("Parser is valid") else: - print("Parser is NOT valid!") - quit() - + print("Parser is NOT valid!") + quit() # Test getting list of valid parsers, and DebugInfoParser's repr print("") for p in bn.debuginfo.DebugInfoParser.get_parsers_for_view(bv): - print(f"`{p.name}` is valid for `{bv}`") + print(f"`{p.name}` is valid for `{bv}`") print("") # Test calling our `parse_info` callback @@ -219,32 +243,31 @@ print("\nEach of the following pairs of prints should be the same\n") print("All types:") for name, t in debug_info.types: - print(f" \"{name}\": `{t}`") + print(f" \"{name}\": `{t}`") print("Types from parser:") for name, t in debug_info.types_from_parser(parser.name): - print(f" \"{name}\": `{t}`") + print(f" \"{name}\": `{t}`") print("") print("All functions:") for func in debug_info.functions: - print(f" {func}") + print(f" {func}") print("Functions from parser:") for func in debug_info.functions_from_parser(parser.name): - print(f" {func}") + print(f" {func}") print("") print("All data variables:") for data_var in debug_info.data_variables: - print(f" {data_var}") + print(f" {data_var}") print("Data variables from parser:") for data_var in debug_info.data_variables_from_parser(parser.name): - print(f" {data_var}") - + print(f" {data_var}") print("Appling debug info!") bv.apply_debug_info(debug_info) @@ -254,16 +277,16 @@ bv.update_analysis_and_wait() print("") print("Types:") for name, t in debug_info.types: - print(f" {bv.get_type_by_name(name)}") + print(f" {bv.get_type_by_name(name)}") print("") print("Functions:") for func in debug_info.functions: - print(f" {bv.get_function_at(func.address)}") + print(f" {bv.get_function_at(func.address)}") print("") print("Data variables:") for data_var in debug_info.data_variables: - print(f" {bv.get_data_var_at(data_var.address)}") + print(f" {bv.get_data_var_at(data_var.address)}") diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py index c96873e1..8166b27a 100755 --- a/python/examples/export_svg.py +++ b/python/examples/export_svg.py @@ -12,119 +12,126 @@ from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxBut from binaryninja.function import DisassemblySettings from binaryninja.plugin import PluginCommand -colors = {'green': [162, 217, 175], 'red': [222, 143, 151], 'blue': [128, 198, 233], 'cyan': [142, 230, 237], 'lightCyan': [ - 176, 221, 228], 'orange': [237, 189, 129], 'yellow': [237, 223, 179], 'magenta': [218, 196, 209], 'none': [74, 74, 74], - 'disabled': [144, 144, 144]} - -escape_table = { - "'": "'", - ">": ">", - "<": "<", - '"': """, - ' ': " " +colors = { + 'green': [162, 217, 175], 'red': [222, 143, 151], 'blue': [128, 198, 233], 'cyan': [142, 230, 237], + 'lightCyan': [176, 221, 228], 'orange': [237, 189, 129], 'yellow': [237, 223, 179], 'magenta': [218, 196, 209], + 'none': [74, 74, 74], 'disabled': [144, 144, 144] } +escape_table = {"'": "'", ">": ">", "<": "<", '"': """, ' ': " "} + def escape(toescape): - # handle extended unicode - toescape = toescape.encode('ascii', 'xmlcharrefreplace') - # still escape the basics - if sys.version_info[0] == 3: - return ''.join(escape_table.get(chr(i), chr(i)) for i in toescape) - else: - return ''.join(escape_table.get(i, i) for i in toescape) + # handle extended unicode + toescape = toescape.encode('ascii', 'xmlcharrefreplace') + # still escape the basics + if sys.version_info[0] == 3: + return ''.join(escape_table.get(chr(i), chr(i)) for i in toescape) + else: + return ''.join(escape_table.get(i, i) for i in toescape) def save_svg(bv, function): - sym = bv.get_symbol_at(function.start) - if sym: - offset = sym.name - else: - offset = "%x" % function.start - path = Path(os.path.dirname(bv.file.filename)) - origname = os.path.basename(bv.file.filename) - filename = path / f'binaryninja-{origname}-{offset}.html' + sym = bv.get_symbol_at(function.start) + if sym: + offset = sym.name + else: + offset = "%x" % function.start + path = Path(os.path.dirname(bv.file.filename)) + origname = os.path.basename(bv.file.filename) + filename = path / f'binaryninja-{origname}-{offset}.html' - functionChoice = TextLineField("Blank to accept default") - # TODO: implement linear disassembly settings and output - modeChoices = ["Graph"] - modeChoiceField = ChoiceField("Mode", modeChoices) - if Settings().get_bool('ui.debugMode'): - formChoices = ["Assembly", "Lifted IL", "LLIL", "LLIL SSA", "Mapped Medium", "Mapped Medium SSA", "MLIL", "MLIL SSA", "HLIL", "HLIL SSA"] - formChoiceField = ChoiceField("Form", formChoices) - else: - formChoices = ["Assembly", "LLIL", "MLIL", "HLIL"] - formChoiceField = ChoiceField("Form", formChoices) + functionChoice = TextLineField("Blank to accept default") + # TODO: implement linear disassembly settings and output + modeChoices = ["Graph"] + modeChoiceField = ChoiceField("Mode", modeChoices) + if Settings().get_bool('ui.debugMode'): + formChoices = [ + "Assembly", "Lifted IL", "LLIL", "LLIL SSA", "Mapped Medium", "Mapped Medium SSA", "MLIL", "MLIL SSA", "HLIL", + "HLIL SSA" + ] + formChoiceField = ChoiceField("Form", formChoices) + else: + formChoices = ["Assembly", "LLIL", "MLIL", "HLIL"] + formChoiceField = ChoiceField("Form", formChoices) - showOpcodes = ChoiceField("Show Opcodes", ["Yes", "No"]) - showAddresses = ChoiceField("Show Addresses", ["Yes", "No"]) + showOpcodes = ChoiceField("Show Opcodes", ["Yes", "No"]) + showAddresses = ChoiceField("Show Addresses", ["Yes", "No"]) - saveFileChoices = SaveFileNameField("Output file", 'HTML files (*.html)', str(filename)) - if not get_form_input([f'Current Function: {offset}', functionChoice, formChoiceField, modeChoiceField, showOpcodes, showAddresses, saveFileChoices], "SVG Export") or saveFileChoices.result is None: - return - if saveFileChoices.result == '': - outputfile = filename - else: - outputfile = saveFileChoices.result - content = render_svg(function, offset, modeChoices[modeChoiceField.result], formChoices[formChoiceField.result], showOpcodes.result == 0, showAddresses.result == 0, origname) - output = open(outputfile, 'w') - output.write(content) - output.close() - result = show_message_box("Open SVG", "Would you like to view the exported SVG?", - buttons=MessageBoxButtonSet.YesNoButtonSet, icon=MessageBoxIcon.QuestionIcon) - if result == MessageBoxButtonResult.YesButton: - # might need more testing, latest py3 on windows seems.... broken with these APIs relative to other platforms - if sys.platform == 'win32': - webbrowser.open(outputfile) - else: - webbrowser.open('file://' + str(outputfile)) + saveFileChoices = SaveFileNameField("Output file", 'HTML files (*.html)', str(filename)) + if not get_form_input([ + f'Current Function: {offset}', functionChoice, formChoiceField, modeChoiceField, showOpcodes, showAddresses, + saveFileChoices + ], "SVG Export") or saveFileChoices.result is None: + return + if saveFileChoices.result == '': + outputfile = filename + else: + outputfile = saveFileChoices.result + content = render_svg( + function, offset, modeChoices[modeChoiceField.result], formChoices[formChoiceField.result], showOpcodes.result == 0, + showAddresses.result == 0, origname + ) + output = open(outputfile, 'w') + output.write(content) + output.close() + result = show_message_box( + "Open SVG", "Would you like to view the exported SVG?", buttons=MessageBoxButtonSet.YesNoButtonSet, + icon=MessageBoxIcon.QuestionIcon + ) + if result == MessageBoxButtonResult.YesButton: + # might need more testing, latest py3 on windows seems.... broken with these APIs relative to other platforms + if sys.platform == 'win32': + webbrowser.open(outputfile) + else: + webbrowser.open('file://' + str(outputfile)) def instruction_data_flow(function, address): - # TODO: Extract data flow information - length = function.view.get_instruction_length(address) - func_bytes = function.view.read(address, length) - if sys.version_info[0] == 3: - hex = func_bytes.hex() - else: - hex = func_bytes.encode('hex') - padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) - return 'Opcode: {bytes}'.format(bytes=padded) + # TODO: Extract data flow information + length = function.view.get_instruction_length(address) + func_bytes = function.view.read(address, length) + if sys.version_info[0] == 3: + hex = func_bytes.hex() + else: + hex = func_bytes.encode('hex') + padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) + return 'Opcode: {bytes}'.format(bytes=padded) def render_svg(function, offset, mode, form, showOpcodes, showAddresses, origname): - settings = DisassemblySettings() - if showOpcodes: - settings.set_option(DisassemblyOption.ShowOpcode, True) - if showAddresses: - settings.set_option(DisassemblyOption.ShowAddress, True) - if form == "LLIL": - graph_type = FunctionGraphType.LowLevelILFunctionGraph - elif form == "LLIL SSA": - graph_type = FunctionGraphType.LowLevelILSSAFormFunctionGraph - elif form == "Lifted IL": - graph_type = FunctionGraphType.LiftedILFunctionGraph - elif form == "Mapped Medium": - graph_type = FunctionGraphType.MappedMediumLevelILFunctionGraph - elif form == "Mapped Medium SSA": - graph_type = FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph - elif form == "MLIL": - graph_type = FunctionGraphType.MediumLevelILFunctionGraph - elif form == "MLIL SSA": - graph_type = FunctionGraphType.MediumLevelILSSAFormFunctionGraph - elif form == "HLIL": - graph_type = FunctionGraphType.HighLevelILFunctionGraph - elif form == "HLIL SSA": - graph_type = FunctionGraphType.HighLevelILSSAFormFunctionGraph - else: - graph_type = FunctionGraphType.NormalFunctionGraph - graph = function.create_graph(graph_type=graph_type, settings=settings) - graph.layout_and_wait() - heightconst = 15 - ratio = 0.48 - widthconst = heightconst * ratio + settings = DisassemblySettings() + if showOpcodes: + settings.set_option(DisassemblyOption.ShowOpcode, True) + if showAddresses: + settings.set_option(DisassemblyOption.ShowAddress, True) + if form == "LLIL": + graph_type = FunctionGraphType.LowLevelILFunctionGraph + elif form == "LLIL SSA": + graph_type = FunctionGraphType.LowLevelILSSAFormFunctionGraph + elif form == "Lifted IL": + graph_type = FunctionGraphType.LiftedILFunctionGraph + elif form == "Mapped Medium": + graph_type = FunctionGraphType.MappedMediumLevelILFunctionGraph + elif form == "Mapped Medium SSA": + graph_type = FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph + elif form == "MLIL": + graph_type = FunctionGraphType.MediumLevelILFunctionGraph + elif form == "MLIL SSA": + graph_type = FunctionGraphType.MediumLevelILSSAFormFunctionGraph + elif form == "HLIL": + graph_type = FunctionGraphType.HighLevelILFunctionGraph + elif form == "HLIL SSA": + graph_type = FunctionGraphType.HighLevelILSSAFormFunctionGraph + else: + graph_type = FunctionGraphType.NormalFunctionGraph + graph = function.create_graph(graph_type=graph_type, settings=settings) + graph.layout_and_wait() + heightconst = 15 + ratio = 0.48 + widthconst = heightconst * ratio - output = ''' + output = '''