diff --git a/python/binaryview.py b/python/binaryview.py index 2f441f349..915117b1b 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -30,7 +30,7 @@ import inspect import os import uuid -from typing import Callable, Generator, Optional, Union, Tuple, List, Mapping, Any, \ +from typing import Callable, Generator, Optional, Union, Tuple, List, Sequence, Mapping, Any, \ Iterator, Iterable, KeysView, ItemsView, ValuesView, Dict, overload from dataclasses import dataclass from enum import IntFlag @@ -88,6 +88,7 @@ InstructionsType = Generator[Tuple[List['_function.InstructionTextToken'], int], None, None] ProgressFuncType = Callable[[int, int], bool] DataMatchCallbackType = Callable[[int, 'databuffer.DataBuffer'], bool] +TextMatchCallbackType = Callable[[int, str, 'lineardisassembly.LinearDisassemblyLine'], bool] LineMatchCallbackType = Callable[[int, 'lineardisassembly.LinearDisassemblyLine'], bool] StringOrType = Union[str, '_types.Type', '_types.TypeBuilder'] @@ -8560,7 +8561,7 @@ def define_user_type(self, name: Optional['_types.QualifiedNameType'], type_obj: type_obj = type_obj.immutable_copy() core.BNDefineUserAnalysisType(self.handle, _name, type_obj.handle) - def define_types(self, types: List[Tuple[str, Optional['_types.QualifiedNameType'], StringOrType]], progress_func: Optional[ProgressFuncType]) -> Mapping[str, '_types.QualifiedName']: + def define_types(self, types: Sequence[Tuple[str, Optional['_types.QualifiedNameType'], StringOrType]], progress_func: Optional[ProgressFuncType]) -> Mapping[str, '_types.QualifiedName']: """ ``define_types`` registers multiple types as though calling :py:func:`define_type` multiple times. The difference with this plural version is that it is optimized for adding many types @@ -8612,7 +8613,7 @@ def define_types(self, types: List[Tuple[str, Optional['_types.QualifiedNameType core.BNFreeStringList(result_ids, result_count) core.BNFreeTypeNameList(result_names, result_count) - def define_user_types(self, types: List[Tuple[Optional['_types.QualifiedNameType'], StringOrType]], progress_func: Optional[ProgressFuncType]): + def define_user_types(self, types: Sequence[Tuple[Optional['_types.QualifiedNameType'], StringOrType]], progress_func: Optional[ProgressFuncType]): """ ``define_user_types`` registers multiple types as though calling :py:func:`define_user_type` multiple times. The difference with this plural version is that it is optimized for adding many types @@ -9535,6 +9536,18 @@ def __next__(self): if (not self.thread.is_alive()) and self.results.empty(): raise StopIteration + @overload + def find_all_data( + self, start: int, end: int, data: bytes, flags: FindFlag = FindFlag.FindCaseSensitive, + progress_func: Optional[ProgressFuncType] = None, match_callback: None = None + ) -> QueueGenerator: ... + + @overload + def find_all_data( + self, start: int, end: int, data: bytes, flags: FindFlag = FindFlag.FindCaseSensitive, + progress_func: Optional[ProgressFuncType] = None, match_callback: DataMatchCallbackType = None + ) -> bool: ... + def find_all_data( self, start: int, end: int, data: bytes, flags: FindFlag = FindFlag.FindCaseSensitive, progress_func: Optional[ProgressFuncType] = None, match_callback: Optional[DataMatchCallbackType] = None @@ -9610,10 +9623,24 @@ def _LinearDisassemblyLine_convertor( core.BNFreeLinearDisassemblyLines(lines, 1) return line + @overload + def find_all_text( + self, start: int, end: int, text: str, settings: Optional[_function.DisassemblySettings] = None, + flags=FindFlag.FindCaseSensitive, graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func=None, + match_callback: None = None + ) -> QueueGenerator: ... + + @overload + def find_all_text( + self, start: int, end: int, text: str, settings: Optional[_function.DisassemblySettings] = None, + flags=FindFlag.FindCaseSensitive, graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func=None, + match_callback: TextMatchCallbackType = None + ) -> bool: ... + def find_all_text( self, start: int, end: int, text: str, settings: Optional[_function.DisassemblySettings] = None, flags=FindFlag.FindCaseSensitive, graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func=None, - match_callback=None + match_callback: Optional[TextMatchCallbackType] = None ) -> Union[QueueGenerator, bool]: """ ``find_all_text`` searches for string ``text`` occurring in the linear view output starting @@ -9679,7 +9706,7 @@ def find_all_text( ctypes.POINTER(core.BNLinearDisassemblyLine) )( lambda ctxt, addr, match, line: - not match_callback(addr, match, self._LinearDisassemblyLine_convertor(line)) is False + not match_callback(addr, core.pyNativeStr(match), self._LinearDisassemblyLine_convertor(line)) is False ) return core.BNFindAllTextWithProgress( @@ -9692,7 +9719,7 @@ def find_all_text( 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))) + lambda ctxt, addr, match, line: results.put((addr, core.pyNativeStr(match), self._LinearDisassemblyLine_convertor(line))) or True ) @@ -9705,6 +9732,20 @@ def find_all_text( return self.QueueGenerator(t, results) + @overload + def find_all_constant( + self, start: int, end: int, constant: int, settings: Optional[_function.DisassemblySettings] = None, + graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func: Optional[ProgressFuncType] = None, + match_callback: None = None + ) -> QueueGenerator: ... + + @overload + def find_all_constant( + self, start: int, end: int, constant: int, settings: Optional[_function.DisassemblySettings] = None, + graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func: Optional[ProgressFuncType] = None, + match_callback: LineMatchCallbackType = None + ) -> bool: ... + def find_all_constant( self, start: int, end: int, constant: int, settings: Optional[_function.DisassemblySettings] = None, graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func: Optional[ProgressFuncType] = None, @@ -11497,6 +11538,12 @@ def __iter__(self): for i in range(_type.count): yield self[i] + @overload + def __getitem__(self, key: Union[str, int]) -> 'TypedDataAccessor': ... + + @overload + def __getitem__(self, key: slice) -> List['TypedDataAccessor']: ... + def __getitem__(self, key: Union[str, int, slice]) -> Union['TypedDataAccessor', List['TypedDataAccessor']]: _type = self.type if isinstance(_type, _types.NamedTypeReferenceType): diff --git a/python/callingconvention.py b/python/callingconvention.py index 2023e37f6..fd06c4573 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -389,11 +389,11 @@ def _get_incoming_reg_value(self, ctxt, reg, func, result): result[0].state = api_obj.state result[0].value = api_obj.value - def _get_incoming_flag_value(self, ctxt, reg, func, result): + def _get_incoming_flag_value(self, ctxt, flag, func, result): try: 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() + flag_name = self.arch.get_reg_name(flag) + api_obj = self.perform_get_incoming_flag_value(flag_name, func_obj)._to_core_struct() except: log_error_for_exception("Unhandled Python exception in CallingConvention._get_incoming_flag_value") api_obj = variable.Undetermined()._to_core_struct() @@ -444,7 +444,7 @@ def perform_get_incoming_reg_value( return variable.Undetermined() def perform_get_incoming_flag_value( - self, reg: 'architecture.RegisterName', func: 'function.Function' + self, flag: 'architecture.FlagName', func: 'function.Function' ) -> 'variable.RegisterValue': return variable.Undetermined() @@ -477,14 +477,14 @@ def get_incoming_reg_value( ) def get_incoming_flag_value( - self, flag: 'architecture.FlagIndex', func: 'function.Function' + self, flag: 'architecture.FlagType', func: 'function.Function' ) -> 'variable.RegisterValue': - reg_num = self.arch.get_flag_index(flag) + flag_index = 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 + core.BNGetIncomingFlagValue(self.handle, flag_index, func_handle), self.arch ) def get_incoming_var_for_parameter_var( diff --git a/python/typeprinter.py b/python/typeprinter.py index 048dec39c..e908666db 100644 --- a/python/typeprinter.py +++ b/python/typeprinter.py @@ -21,7 +21,7 @@ import ctypes import dataclasses from json import dumps -from typing import List, Tuple, Optional, Any +from typing import List, Sequence, Tuple, Optional, Any import sys import traceback @@ -305,7 +305,7 @@ def _free_lines(self, ctxt, lines, count): log_error_for_exception("Unhandled Python exception in TypePrinter._free_lines") return False - def _default_print_all_types(self, types_: List[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: + def _default_print_all_types(self, types_: Sequence[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: cpp_names = (core.BNQualifiedName * len(types_))() cpp_types = (ctypes.POINTER(core.BNType) * len(types_))() @@ -427,7 +427,7 @@ def get_type_lines(self, type: types.Type, container: 'typecontainer.TypeContain """ raise NotImplementedError() - def print_all_types(self, types: List[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: + def print_all_types(self, types: Sequence[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: """ Print all types to a single big string, including headers, sections, etc @@ -541,7 +541,7 @@ def get_type_lines(self, type: types.Type, container: 'typecontainer.TypeContain core.BNFreeTypeDefinitionLineList(core_lines, count.value) return lines - def print_all_types(self, types_: List[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: + def print_all_types(self, types_: Sequence[Tuple[types.QualifiedNameType, types.Type]], data: binaryview.BinaryView, padding_cols = 64, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> str: cpp_names = (core.BNQualifiedName * len(types_))() cpp_types = (ctypes.POINTER(core.BNType) * len(types_))() diff --git a/python/types.py b/python/types.py index 0da212d3f..c9fbe4d74 100644 --- a/python/types.py +++ b/python/types.py @@ -20,7 +20,7 @@ import ctypes import typing -from typing import Generator, List, Union, Tuple, Optional, Iterable, Dict, Generic, TypeVar, Callable +from typing import Generator, List, Union, Tuple, Optional, Iterable, Dict, Generic, TypeVar, Callable, Self, overload from dataclasses import dataclass import uuid @@ -85,7 +85,7 @@ def convert_integer(value: ctypes.c_uint64, signed: bool, width: int) -> int: return func[bool(signed)][width](value).value class QualifiedName: - def __init__(self, name: Optional[QualifiedNameType] = None): + def __init__(self, name: Optional[QualifiedNameType] = None, separator: str = "::"): self._name: List[str] = [] if isinstance(name, str): self._name = [name] @@ -99,9 +99,10 @@ def __init__(self, name: Optional[QualifiedNameType] = None): self._name.append(i.decode("utf-8")) else: self._name.append(str(i)) + self._separator = separator def __str__(self): - return "::".join(self.name) + return self.separator.join(self.name) def __repr__(self): return repr(str(self)) @@ -115,7 +116,7 @@ def __eq__(self, other): elif isinstance(other, list): return self.name == other elif isinstance(other, self.__class__): - return self.name == other.name + return self.name == other.name and self.separator == other.separator return NotImplemented def __ne__(self, other): @@ -163,7 +164,7 @@ def _to_core_struct(self) -> core.BNQualifiedName: name_list[i] = self.name[i].encode("utf-8") result.name = name_list result.nameCount = len(self.name) - result.join = "::".encode("utf-8") + result.join = self.separator.encode("utf-8") return result @staticmethod @@ -181,6 +182,14 @@ def name(self) -> List[str]: def name(self, value: List[str]) -> None: self._name = value + @property + def separator(self) -> str: + return self._separator + + @separator.setter + def separator(self, value: str) -> None: + self._separator = value + @staticmethod def escape(name: QualifiedNameType, escaping: TokenEscapingType) -> str: return core.BNEscapeTypeName(str(QualifiedName(name)), escaping) @@ -651,7 +660,7 @@ def immutable_copy(self): } return Types[self.type_class](self._finalized, self.platform, self.confidence) - def mutable_copy(self) -> 'TypeBuilder': + def mutable_copy(self) -> Self: return self @classmethod @@ -719,7 +728,7 @@ def named_type_from_type( @staticmethod def named_type_from_type_and_id( - type_id: str, name: QualifiedNameType, type: Optional['Type'] = None + type_id: str, name: QualifiedNameType, type: Optional[SomeType] = None ) -> 'NamedTypeReferenceBuilder': return NamedTypeReferenceBuilder.named_type_from_type_and_id(type_id, name, type) @@ -731,7 +740,7 @@ def named_type_from_registered_type( @staticmethod def pointer( - arch: 'architecture.Architecture', type: 'Type', const: BoolWithConfidenceType = BoolWithConfidence(False), + arch: 'architecture.Architecture', type: SomeType, const: BoolWithConfidenceType = BoolWithConfidence(False), volatile: BoolWithConfidenceType = BoolWithConfidence(False), ref_type: ReferenceType = ReferenceType.PointerReferenceType ) -> 'PointerBuilder': @@ -739,19 +748,19 @@ def pointer( @staticmethod def pointer_of_width( - width: _int, type: 'Type', const: BoolWithConfidenceType = BoolWithConfidence(False), + width: _int, type: SomeType, const: BoolWithConfidenceType = BoolWithConfidence(False), volatile: BoolWithConfidenceType = BoolWithConfidence(False), ref_type: ReferenceType = ReferenceType.PointerReferenceType ) -> 'PointerBuilder': return PointerBuilder.create(type, width, None, const, volatile, ref_type) @staticmethod - def array(type: 'Type', count: _int) -> 'ArrayBuilder': + def array(type: SomeType, count: _int) -> 'ArrayBuilder': return ArrayBuilder.create(type, count) @staticmethod def function( - ret: Optional['Type'] = None, params: Optional[ParamsType] = None, + ret: Optional[SomeType] = None, params: Optional[ParamsType] = None, calling_convention: Optional['callingconvention.CallingConvention'] = None, variable_arguments: Optional[BoolWithConfidenceType] = None, stack_adjust: Optional[OffsetWithConfidenceType] = None @@ -989,7 +998,7 @@ def create( class PointerBuilder(TypeBuilder): @classmethod def create( - cls, type: 'Type', width: int = 4, arch: Optional['architecture.Architecture'] = None, + cls, type: SomeType, width: int = 4, arch: Optional['architecture.Architecture'] = None, const: BoolWithConfidenceType = False, volatile: BoolWithConfidenceType = False, ref_type: ReferenceType = ReferenceType.PointerReferenceType, platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence @@ -1802,7 +1811,13 @@ def __iter__(self) -> Generator[EnumerationMember, None, None]: for member in self.members: yield member - def __getitem__(self, value: Union[str, int, slice]): + @overload + def __getitem__(self, value: Union[str, int]) -> EnumerationMember: ... + + @overload + def __getitem__(self, value: slice) -> List[EnumerationMember]: ... + + def __getitem__(self, value: Union[str, int, slice]) -> EnumerationMember: if isinstance(value, str): for member in self.members: if member.name == value: @@ -1889,7 +1904,7 @@ def named_type( @staticmethod def named_type_from_type_and_id( - type_id: str, name: QualifiedNameType, type: Optional['Type'] = None + type_id: str, name: QualifiedNameType, type: Optional[SomeType] = None ) -> 'NamedTypeReferenceBuilder': if type is None: return NamedTypeReferenceBuilder.create(NamedTypeReferenceClass.UnknownNamedTypeClass, type_id, name) @@ -2271,7 +2286,7 @@ def mutable_copy(self) -> 'TypeBuilder': assert builder_handle is not None, "core.BNCreateTypeBuilderFromType returned None" return TypeBuilders[self.type_class](builder_handle, self.platform, self.confidence) - def immutable_copy(self) -> 'Type': + def immutable_copy(self) -> Self: return self def get_builder(self, bv: 'binaryview.BinaryView') -> 'MutableTypeBuilder': @@ -2396,12 +2411,12 @@ def named_type(named_type: 'NamedTypeReferenceBuilder') -> 'NamedTypeReferenceTy return result @staticmethod - def named_type_from_type(name: QualifiedNameType, type: 'Type') -> 'NamedTypeReferenceType': + def named_type_from_type(name: QualifiedNameType, type: SomeType) -> 'NamedTypeReferenceType': return NamedTypeReferenceType.create_from_type(name, type) @staticmethod def named_type_from_type_and_id( - type_id: str, name: QualifiedNameType, type: Optional['Type'] = None + type_id: str, name: QualifiedNameType, type: Optional[SomeType] = None ) -> 'NamedTypeReferenceType': return NamedTypeReferenceType.create_from_type(name, type, type_id) @@ -2421,7 +2436,7 @@ def enumeration_type( @staticmethod def pointer( - arch: 'architecture.Architecture', type: 'Type', const: BoolWithConfidenceType = BoolWithConfidence(False), + arch: 'architecture.Architecture', type: SomeType, const: BoolWithConfidenceType = BoolWithConfidence(False), volatile: BoolWithConfidenceType = BoolWithConfidence(False), ref_type: ReferenceType = ReferenceType.PointerReferenceType, width: _int = None ) -> 'PointerType': @@ -2434,7 +2449,7 @@ def pointer( @staticmethod def pointer_of_width( - width: _int, type: 'Type', const: BoolWithConfidenceType = False, volatile: BoolWithConfidenceType = False, + width: _int, type: SomeType, const: BoolWithConfidenceType = False, volatile: BoolWithConfidenceType = False, ref_type: ReferenceType = ReferenceType.PointerReferenceType ) -> 'PointerType': return PointerType.create_with_width(width, type, const, volatile, ref_type) @@ -3339,7 +3354,7 @@ def create_from_handle(cls, ntr_handle, alignment: int = 0, @classmethod def create_from_type( - cls, name: QualifiedNameType, type: Optional[Type], guid: Optional[str] = None, + cls, name: QualifiedNameType, type: Optional[SomeType], guid: Optional[str] = None, platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence, const: BoolWithConfidenceType = False, volatile: BoolWithConfidenceType = False ) -> 'NamedTypeReferenceType':