diff options
| author | Peter LaFosse <peter@vector35.com> | 2021-07-07 08:26:29 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2021-09-05 10:09:09 -0400 |
| commit | 764063b2b44dbeba5f2f318c971e4f4acfb48427 (patch) | |
| tree | e014fe6a859b97a653cef80dc9db66a06c706c37 | |
| parent | d376db916f5fc83f9e654edf23364d200839ac50 (diff) | |
Refactor Python Types
Remove _mutable types
| -rw-r--r-- | architecture.cpp | 2 | ||||
| -rw-r--r-- | binaryninjaapi.h | 11 | ||||
| -rw-r--r-- | binaryninjacore.h | 24 | ||||
| -rw-r--r-- | python/architecture.py | 4 | ||||
| -rw-r--r-- | python/basicblock.py | 3 | ||||
| -rw-r--r-- | python/binaryview.py | 536 | ||||
| -rw-r--r-- | python/databuffer.py | 3 | ||||
| -rw-r--r-- | python/datarender.py | 12 | ||||
| -rw-r--r-- | python/demangle.py | 4 | ||||
| -rw-r--r-- | python/examples/triage/imports.py | 2 | ||||
| -rw-r--r-- | python/filemetadata.py | 3 | ||||
| -rw-r--r-- | python/flowgraph.py | 9 | ||||
| -rw-r--r-- | python/function.py | 34 | ||||
| -rw-r--r-- | python/highlevelil.py | 2 | ||||
| -rw-r--r-- | python/lineardisassembly.py | 6 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 2 | ||||
| -rw-r--r-- | python/platform.py | 28 | ||||
| -rw-r--r-- | python/plugin.py | 6 | ||||
| -rw-r--r-- | python/pluginmanager.py | 6 | ||||
| -rw-r--r-- | python/scriptingprovider.py | 3 | ||||
| -rw-r--r-- | python/typelibrary.py | 33 | ||||
| -rw-r--r-- | python/types.py | 2212 | ||||
| -rw-r--r-- | python/variable.py | 2 | ||||
| -rw-r--r-- | rust/src/lib.rs | 2 | ||||
| -rw-r--r-- | suite/testcommon.py | 70 | ||||
| -rw-r--r-- | type.cpp | 16 |
26 files changed, 1902 insertions, 1133 deletions
diff --git a/architecture.cpp b/architecture.cpp index f64c87d6..0ef171f5 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -849,7 +849,7 @@ size_t Architecture::GetInstructionAlignment() const size_t Architecture::GetMaxInstructionLength() const { - return BN_DEFAULT_NSTRUCTION_LENGTH; + return BN_DEFAULT_INSTRUCTION_LENGTH; } diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 62fdb965..ba955230 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2820,7 +2820,8 @@ __attribute__ ((format (printf, 1, 2))) static Ref<Type> NamedType(const QualifiedName& name, Type* type); static Ref<Type> NamedType(const std::string& id, const QualifiedName& name, Type* type); static Ref<Type> NamedType(BinaryView* view, const QualifiedName& name); - static Ref<Type> EnumerationType(Architecture* arch, Enumeration* enm, size_t width = 0, bool issigned = false); + static Ref<Type> EnumerationType(Architecture* arch, Enumeration* enm, size_t width = 0, bool isSigned = false); + static Ref<Type> EnumerationType(Enumeration* enm, size_t width, bool isSigned = false); static Ref<Type> PointerType(Architecture* arch, const Confidence<Ref<Type>>& type, const Confidence<bool>& cnst = Confidence<bool>(false, 0), const Confidence<bool>& vltl = Confidence<bool>(false, 0), BNReferenceType refType = PointerReferenceType); @@ -3044,7 +3045,7 @@ __attribute__ ((format (printf, 1, 2))) size_t GetAlignment() const; bool IsPacked() const; bool IsUnion() const; - BNStructureType GetStructureType() const; + BNStructureVariant GetStructureType() const; Ref<Structure> WithReplacedStructure(Structure* from, Structure* to); Ref<Structure> WithReplacedEnumeration(Enumeration* from, Enumeration* to); @@ -3058,7 +3059,7 @@ __attribute__ ((format (printf, 1, 2))) public: StructureBuilder(); StructureBuilder(BNStructureBuilder* s); - StructureBuilder(BNStructureType type, bool packed = false); + StructureBuilder(BNStructureVariant type, bool packed = false); StructureBuilder(const StructureBuilder& s); StructureBuilder(StructureBuilder&& s); StructureBuilder(Structure* s); @@ -3081,8 +3082,8 @@ __attribute__ ((format (printf, 1, 2))) bool IsPacked() const; StructureBuilder& SetPacked(bool packed); bool IsUnion() const; - StructureBuilder& SetStructureType(BNStructureType type); - BNStructureType GetStructureType() const; + StructureBuilder& SetStructureType(BNStructureVariant type); + BNStructureVariant GetStructureType() const; StructureBuilder& AddMember(const Confidence<Ref<Type>>& type, const std::string& name); StructureBuilder& AddMemberAtOffset(const Confidence<Ref<Type>>& type, const std::string& name, uint64_t offset, bool overwriteExisting = true); diff --git a/binaryninjacore.h b/binaryninjacore.h index 77107f3d..42f60158 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -21,8 +21,9 @@ #ifndef __BINARYNINJACORE_H__ #define __BINARYNINJACORE_H__ -#include <stdint.h> -#include <stddef.h> +#include <cstdint> +#include <cstddef> +#include <cstdlib> // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, @@ -63,7 +64,7 @@ #endif #define BN_MAX_INSTRUCTION_LENGTH 256 -#define BN_DEFAULT_NSTRUCTION_LENGTH 16 +#define BN_DEFAULT_INSTRUCTION_LENGTH 16 #define BN_DEFAULT_OPCODE_DISPLAY 8 #define BN_MAX_INSTRUCTION_BRANCHES 3 @@ -637,7 +638,7 @@ extern "C" EnumNamedTypeClass = 5 }; - enum BNStructureType + enum BNStructureVariant { ClassStructureType = 0, StructStructureType = 1, @@ -1671,7 +1672,7 @@ extern "C" SidebarWidgetBackgroundColor }; - // The following edge styles map to QT's Qt::PenStyle enumeration + // The following edge styles map to Qt's Qt::PenStyle enumeration enum BNEdgePenStyle { NoPen = 0, // no line at all. @@ -4671,6 +4672,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNType* BNCreateWideCharType(size_t width, const char* altName); BINARYNINJACOREAPI BNType* BNCreateStructureType(BNStructure* s); BINARYNINJACOREAPI BNType* BNCreateEnumerationType(BNArchitecture* arch, BNEnumeration* e, size_t width, bool isSigned); + BINARYNINJACOREAPI BNType* BNCreateEnumerationTypeOfWidth(BNEnumeration* e, size_t width, bool isSigned); BINARYNINJACOREAPI BNType* BNCreatePointerType(BNArchitecture* arch, const BNTypeWithConfidence* const type, BNBoolWithConfidence* cnst, BNBoolWithConfidence* vltl, BNReferenceType refType); BINARYNINJACOREAPI BNType* BNCreatePointerTypeOfWidth(size_t width, const BNTypeWithConfidence* const type, @@ -4694,6 +4696,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNTypeBuilder* BNCreateStructureTypeBuilderWithBuilder(BNStructureBuilder* s); BINARYNINJACOREAPI BNTypeBuilder* BNCreateEnumerationTypeBuilder(BNArchitecture* arch, BNEnumeration* e, size_t width, bool isSigned); BINARYNINJACOREAPI BNTypeBuilder* BNCreateEnumerationTypeBuilderWithBuilder(BNArchitecture* arch, BNEnumerationBuilder* e, size_t width, bool isSigned); + BINARYNINJACOREAPI BNTypeBuilder* BNCreateEnumerationTypeBuilderOfWidth(BNEnumeration* e, size_t width, bool isSigned); BINARYNINJACOREAPI BNTypeBuilder* BNCreatePointerTypeBuilder(BNArchitecture* arch, const BNTypeWithConfidence* const type, BNBoolWithConfidence* cnst, BNBoolWithConfidence* vltl, BNReferenceType refType); BINARYNINJACOREAPI BNTypeBuilder* BNCreatePointerTypeBuilderOfWidth(size_t width, const BNTypeWithConfidence* const type, @@ -4733,6 +4736,8 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeStackAdjustment(BNType* type); BINARYNINJACOREAPI BNQualifiedName BNTypeGetStructureName(BNType* type); BINARYNINJACOREAPI BNNamedTypeReference* BNGetRegisteredTypeName(BNType* type); + BINARYNINJACOREAPI BNReferenceType BNTypeGetReferenceType(BNType* type); + BINARYNINJACOREAPI char* BNGetTypeAlternateName(BNType* type); BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform); BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform); @@ -4779,6 +4784,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNTypeBuilderSetVolatile(BNTypeBuilder* type, BNBoolWithConfidence* vltl); BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeBuilderStackAdjustment(BNTypeBuilder* type); BINARYNINJACOREAPI BNQualifiedName BNTypeBuilderGetStructureName(BNTypeBuilder* type); + BINARYNINJACOREAPI BNReferenceType BNTypeBuilderGetReferenceType(BNTypeBuilder* type); BINARYNINJACOREAPI char* BNGetTypeBuilderString(BNTypeBuilder* type, BNPlatform* platform); BINARYNINJACOREAPI char* BNGetTypeBuilderStringBeforeName(BNTypeBuilder* type, BNPlatform* platform); @@ -4816,7 +4822,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNQualifiedName BNGetTypeReferenceBuilderName(BNNamedTypeReferenceBuilder* nt); BINARYNINJACOREAPI BNStructureBuilder* BNCreateStructureBuilder(void); - BINARYNINJACOREAPI BNStructureBuilder* BNCreateStructureBuilderWithOptions(BNStructureType type, bool packed); + BINARYNINJACOREAPI BNStructureBuilder* BNCreateStructureBuilderWithOptions(BNStructureVariant type, bool packed); BINARYNINJACOREAPI BNStructureBuilder* BNCreateStructureBuilderFromStructure(BNStructure* s); BINARYNINJACOREAPI BNStructureBuilder* BNDuplicateStructureBuilder(BNStructureBuilder* s); BINARYNINJACOREAPI BNStructure* BNFinalizeStructureBuilder(BNStructureBuilder* s); @@ -4833,7 +4839,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI size_t BNGetStructureAlignment(BNStructure* s); BINARYNINJACOREAPI bool BNIsStructurePacked(BNStructure* s); BINARYNINJACOREAPI bool BNIsStructureUnion(BNStructure* s); - BINARYNINJACOREAPI BNStructureType BNGetStructureType(BNStructure* s); + BINARYNINJACOREAPI BNStructureVariant BNGetStructureType(BNStructure* s); BINARYNINJACOREAPI BNStructure* BNStructureWithReplacedStructure(BNStructure* s, BNStructure* from, BNStructure* to); BINARYNINJACOREAPI BNStructure* BNStructureWithReplacedEnumeration(BNStructure* s, BNEnumeration* from, BNEnumeration* to); @@ -4850,8 +4856,8 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI bool BNIsStructureBuilderPacked(BNStructureBuilder* s); BINARYNINJACOREAPI void BNSetStructureBuilderPacked(BNStructureBuilder* s, bool packed); BINARYNINJACOREAPI bool BNIsStructureBuilderUnion(BNStructureBuilder* s); - BINARYNINJACOREAPI void BNSetStructureBuilderType(BNStructureBuilder* s, BNStructureType type); - BINARYNINJACOREAPI BNStructureType BNGetStructureBuilderType(BNStructureBuilder* s); + BINARYNINJACOREAPI void BNSetStructureBuilderType(BNStructureBuilder* s, BNStructureVariant type); + BINARYNINJACOREAPI BNStructureVariant BNGetStructureBuilderType(BNStructureBuilder* s); BINARYNINJACOREAPI void BNAddStructureBuilderMember(BNStructureBuilder* s, const BNTypeWithConfidence* const type, const char* name); BINARYNINJACOREAPI void BNAddStructureBuilderMemberAtOffset(BNStructureBuilder* s, diff --git a/python/architecture.py b/python/architecture.py index 079d080d..fdec7fbf 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -2210,7 +2210,7 @@ class CoreArchitecture(Architecture): input_list = [] for j in range(0, input_count.value): input_name = inputs[j].name - type_obj = types.Type(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() @@ -2218,7 +2218,7 @@ 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(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] diff --git a/python/basicblock.py b/python/basicblock.py index 4aca6de5..47021e66 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -59,7 +59,8 @@ class BasicBlock: self._instLengths:Optional[List[int]] = None def __del__(self): - core.BNFreeBasicBlock(self.handle) + if core is not None: + core.BNFreeBasicBlock(self.handle) def __repr__(self): arch = self.arch diff --git a/python/binaryview.py b/python/binaryview.py index 4c57131e..33983045 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -29,8 +29,8 @@ import json import inspect import os from pathlib import Path -from typing import Callable, Generator, Optional, Union, Tuple, List, Mapping -from dataclasses import dataclass +from typing import Callable, Generator, Optional, Union, Tuple, List, Mapping, Any +from dataclasses import dataclass, make_dataclass from collections import defaultdict, OrderedDict @@ -68,6 +68,7 @@ from . import platform as _platform PathType = Union[str, os.PathLike] InstructionsType = Generator[Tuple[List['_function.InstructionTextToken'], int], None, None] NotificationType = Mapping['BinaryDataNotification', 'BinaryDataNotificationCallbacks'] +ProgressFuncType = Callable[[int, int], bool] class ReferenceSource: def __init__(self, func:Optional['_function.Function'], arch:Optional['architecture.Architecture'], @@ -285,7 +286,8 @@ class AnalysisCompletionEvent: def __del__(self): if id(self) in self.__class__._pending_analysis_completion_events: del self.__class__._pending_analysis_completion_events[id(self)] - core.BNFreeAnalysisCompletionEvent(self.handle) + if core is not None: + core.BNFreeAnalysisCompletionEvent(self.handle) def _notify(self, ctxt): if id(self) in self.__class__._pending_analysis_completion_events: @@ -656,21 +658,21 @@ class BinaryDataNotificationCallbacks: 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(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.log_error(traceback.format_exc()) 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(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.log_error(traceback.format_exc()) 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(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.log_error(traceback.format_exc()) @@ -763,7 +765,8 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): return self.create(data) @classmethod - def get_view_of_file(cls, filename:PathType, update_analysis:bool=True, progress_func:Callable[[int, int], bool]=None): + 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 @@ -807,7 +810,8 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass): return bv @classmethod - def get_view_of_file_with_options(cls, filename, update_analysis=True, progress_func=None, options={}): + 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 \ @@ -1013,7 +1017,8 @@ class Segment: self.handle = handle def __del__(self): - core.BNFreeSegment(self.handle) + if core is not None: + core.BNFreeSegment(self.handle) def __repr__(self): r ="r" if self.readable else "-" @@ -1110,7 +1115,8 @@ class Section: self.handle = handle def __del__(self): - core.BNFreeSection(self.handle) + if core is not None: + core.BNFreeSection(self.handle) def __repr__(self): return "<section {self.name}: {self.start:#x}-{self.end:#x}>" @@ -1181,7 +1187,8 @@ class TagType: self.handle = handle def __del__(self): - core.BNFreeTagType(self.handle) + if core is not None: + core.BNFreeTagType(self.handle) def __repr__(self): return f"<tag type {self.name}: {self.icon}>" @@ -1246,7 +1253,8 @@ class Tag: self.handle = handle def __del__(self): - core.BNFreeTag(self.handle) + if core is not None: + core.BNFreeTag(self.handle) def __repr__(self): return "<tag {self.type.icon} {self.type.name}: {self.data}>" @@ -1401,6 +1409,8 @@ class BinaryView: self.file.close() def __del__(self): + if core is None: + return for i in self._notifications.values(): i._unregister() core.BNFreeBinaryView(self.handle) @@ -1966,20 +1976,20 @@ class BinaryView: return result @property - def types(self): - """List of defined types (read-only)""" + def types(self) -> Mapping['_types.QualifiedName', '_types.Type']: + """Mapping of type names and types (read-only)""" count = ctypes.c_ulonglong(0) type_list = core.BNGetAnalysisTypeList(self.handle, count) assert type_list is not None, "core.BNGetAnalysisTypeList returned None" result = {} for i in range(0, count.value): name = _types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = _types.Type(core.BNNewTypeReference(type_list[i].type), platform = self.platform) + result[name] = _types.Type.create(core.BNNewTypeReference(type_list[i].type), platform = self.platform) core.BNFreeTypeList(type_list, count.value) return result @property - def type_names(self): + def type_names(self) -> List['_types.Type']: """List of defined type names (read-only)""" count = ctypes.c_ulonglong(0) name_list = core.BNGetAnalysisTypeNames(self.handle, count, "") @@ -2730,13 +2740,30 @@ class BinaryView: >>> #Opening a x86_64 Mach-O binary >>> bv = BinaryViewType['Raw'].open("/bin/ls") #note that we are using open instead of get_view_of_file to get the raw view >>> bv.read(0,4) - \'\\xcf\\xfa\\xed\\xfe\' + b\'\\xcf\\xfa\\xed\\xfe\' """ if (addr < 0) or (length < 0): raise ValueError("length and address must both be positive") 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: + _endian = self.endianness + if endian is not None: + _endian = endian + data = self.read(address, size) + if len(data) != size: + raise ValueError(f"Couldn't read {size} bytes from address: {address:#x}") + return StructuredDataValue.int_from_bytes(data, size, sign, _endian) + + def read_pointer(self, address:int, size=None) -> int: + _size = size + if size is None: + if self.arch is None: + raise ValueError("Can't read pointer for BinaryView without an architecture") + _size = self.arch.address_size + return self.read_int(address, _size, False, self.endianness) + def write(self, addr:int, data:bytes) -> int: """ ``write`` writes the bytes in ``data`` to the virtual address ``addr``. @@ -2748,11 +2775,11 @@ class BinaryView: :Example: >>> bv.read(0,4) - 'BBBB' - >>> bv.write(0, "AAAA") + b'BBBB' + >>> bv.write(0, b"AAAA") 4 >>> bv.read(0,4) - 'AAAA' + b'AAAA' """ if not (isinstance(data, bytes) or isinstance(data, bytearray) or isinstance(data, str)): raise TypeError("Must be bytes, bytearray, or str") @@ -3122,9 +3149,7 @@ class BinaryView: >>> bv.define_data_var(bv.entry_point, t[0]) >>> """ - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNDefineDataVariable(self.handle, addr, tc) def define_user_data_var(self, addr, var_type): @@ -3142,9 +3167,7 @@ class BinaryView: >>> bv.define_user_data_var(bv.entry_point, t[0]) >>> """ - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNDefineUserDataVariable(self.handle, addr, tc) def undefine_data_var(self, addr): @@ -3830,8 +3853,8 @@ class BinaryView: for i in range(0, count.value): result[refs[i].offset] = [] for j in range(0, refs[i].count): - typeObj = _types.Type(core.BNNewTypeReference(refs[i].types[j].type),\ - confidence = 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) core.BNFreeTypeFieldReferenceTypeInfo(refs, count.value) @@ -3864,7 +3887,7 @@ class BinaryView: core.BNFreeTypeFieldReferenceSizes(refs, count.value) return result - def get_types_referenced(self, name, offset): + 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. @@ -3879,37 +3902,37 @@ class BinaryView: >>> """ count = ctypes.c_ulonglong(0) - name = _types.QualifiedName(name)._get_core_struct() - refs = core.BNGetTypesReferenced(self.handle, name, offset, count) + _name = _types.QualifiedName(name)._get_core_struct() + refs = core.BNGetTypesReferenced(self.handle, _name, offset, count) assert refs is not None, "core.BNGetTypesReferenced returned None" + try: + result = [] + for i in range(0, count.value): + typeObj = _types.Type.create(core.BNNewTypeReference(refs[i].type),\ + confidence = refs[i].confidence) + result.append(typeObj) + return result + finally: + core.BNFreeTypeFieldReferenceTypes(refs, count.value) - result = [] - for i in range(0, count.value): - typeObj = _types.Type(core.BNNewTypeReference(refs[i].type),\ - confidence = refs[i].confidence) - result.append(typeObj) - - core.BNFreeTypeFieldReferenceTypes(refs, count.value) - return result - - def create_structure_from_offset_access(self, name): + def create_structure_from_offset_access(self, name:'_types.QualifiedName') -> '_types.StructureType': newMemberAdded = ctypes.c_bool(False) - name = _types.QualifiedName(name)._get_core_struct() - struct = core.BNCreateStructureFromOffsetAccess(self.handle, name, newMemberAdded) + _name = _types.QualifiedName(name)._get_core_struct() + struct = core.BNCreateStructureFromOffsetAccess(self.handle, _name, newMemberAdded) if struct is None: - return None - return _types.Structure(struct) + raise Exception("BNCreateStructureFromOffsetAccess failed to create struct from offsets") + return _types.StructureType.from_core_struct(struct) - def create_structure_member_from_access(self, name, offset): - name = _types.QualifiedName(name)._get_core_struct() - result = core.BNCreateStructureMemberFromAccess(self.handle, name, offset) + def create_structure_member_from_access(self, name:'_types.QualifiedName', offset:int) -> '_types.Type': + _name = _types.QualifiedName(name)._get_core_struct() + result = core.BNCreateStructureMemberFromAccess(self.handle, _name, offset) if not result.type: - return None + raise Exception("BNCreateStructureMemberFromAccess failed to create struct member offsets") - return _types.Type(core.BNNewTypeReference(result.type),\ + return _types.Type.create(core.BNNewTypeReference(result.type),\ confidence = result.confidence) - def get_callers(self, addr): + 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. @@ -3942,7 +3965,7 @@ class BinaryView: finally: core.BNFreeCodeReferences(refs, count.value) - def get_callees(self, addr, func=None, arch=None): + 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 @@ -3971,7 +3994,6 @@ class BinaryView: core.BNFreeAddressList(refs) return result - def get_symbol_at(self, addr, namespace=None): """ ``get_symbol_at`` returns the Symbol at the provided virtual address. @@ -5497,7 +5519,7 @@ class BinaryView: error_str = errors.value.decode("utf-8") core.free_string(errors) raise SyntaxError(error_str) - type_obj = _types.Type(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) core.BNFreeQualifiedNameAndType(result) return type_obj, name @@ -5536,13 +5558,13 @@ class BinaryView: 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(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(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(core.BNNewTypeReference(parse.functions[i].type), platform = self.platform) + functions[name] = _types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform = self.platform) core.BNFreeTypeParserResult(parse) return _types.TypeParserResult(type_dict, variables, functions) @@ -5612,7 +5634,7 @@ class BinaryView: obj = core.BNGetAnalysisTypeByName(self.handle, name) if not obj: return None - return _types.Type(obj, platform = self.platform) + return _types.Type.create(obj, platform = self.platform) def get_type_by_id(self, id): """ @@ -5633,7 +5655,7 @@ class BinaryView: obj = core.BNGetAnalysisTypeById(self.handle, id) if not obj: return None - return _types.Type(obj, platform = self.platform) + return _types.Type.create(obj, platform = self.platform) def get_type_name_by_id(self, id): """ @@ -5723,7 +5745,7 @@ class BinaryView: name = _types.QualifiedName(name)._get_core_struct() return core.BNIsAnalysisTypeAutoDefined(self.handle, name) - def define_type(self, type_id, default_name, type_obj): + def define_type(self, type_id:str, default_name:'_types.QualifiedName', type_obj:'_types.Type'): """ ``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. @@ -5746,7 +5768,7 @@ class BinaryView: core.BNFreeQualifiedName(reg_name) return result - def define_user_type(self, name, type_obj): + def define_user_type(self, name:Union[str,'_types.QualifiedName'], type_obj:'_types.Type') -> 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`. @@ -5761,8 +5783,9 @@ class BinaryView: >>> bv.get_type_by_name(name) <type: int32_t> """ - name = _types.QualifiedName(name)._get_core_struct() - core.BNDefineUserAnalysisType(self.handle, name, type_obj.handle) + if isinstance(name, str): + name = _types.QualifiedName(name) + core.BNDefineUserAnalysisType(self.handle, name._get_core_struct(), type_obj.handle) def undefine_type(self, type_id): """ @@ -5848,7 +5871,7 @@ class BinaryView: handle = core.BNBinaryViewImportTypeLibraryType(self.handle, None if lib is None else lib.handle, name._get_core_struct()) if handle is None: return None - return _types.Type(handle, platform = self.platform) + return _types.Type.create(handle, platform = self.platform) def import_library_object(self, name, lib = None): """ @@ -5869,7 +5892,7 @@ class BinaryView: handle = core.BNBinaryViewImportTypeLibraryObject(self.handle, None if lib is None else lib.handle, name._get_core_struct()) if handle is None: return None - return _types.Type(handle, platform = self.platform) + return _types.Type.create(handle, platform = self.platform) def export_type_to_library(self, lib, name, type_obj): """ @@ -6725,7 +6748,8 @@ class BinaryReader: print(self._handle) def __del__(self): - core.BNFreeBinaryReader(self._handle) + if core is not None: + core.BNFreeBinaryReader(self._handle) def __eq__(self, other): if not isinstance(other, self.__class__): @@ -7046,7 +7070,8 @@ class BinaryWriter: core.BNSetBinaryWriterEndianness(self._handle, endian) def __del__(self): - core.BNFreeBinaryWriter(self._handle) + if core is not None: + core.BNFreeBinaryWriter(self._handle) def __eq__(self, other): if not isinstance(other, self.__class__): @@ -7263,184 +7288,195 @@ class BinaryWriter: core.BNSeekBinaryWriterRelative(self._handle, offset) +@dataclass class StructuredDataValue: - def __init__(self, type, address, value, endian): - self._type = type - self._address = address - self._value = value - self._endian = endian + type:'_types.Type' + value:bytes + endian:Endianness def __str__(self): - decode_str = "{}B".format(self._type.width) - return ' '.join(["{:02x}".format(x) for x in struct.unpack(decode_str, self._value)]) + decode_str = "{}B".format(self.type.width) + return ' '.join(["{:02x}".format(x) for x in struct.unpack(decode_str, self.value)]) def __repr__(self): - return f"<StructuredDataValue type:{self._type} value:{self}>" + return f"<StructuredDataValue type:{self.type} value:{self}>" def __int__(self): - if self._type.width == 1: - if self._endian == Endianness.LittleEndian: - code = "<B" - else: - code = ">B" - elif self._type.width == 2: - if self._endian == Endianness.LittleEndian: - code = "<H" - else: - code = ">H" - elif self._type.width == 4: - if self._endian == Endianness.LittleEndian: - code = "<I" - else: - code = ">I" - elif self._type.width == 8: - if self._endian == Endianness.LittleEndian: - code = "<Q" - else: - code = ">Q" + if isinstance(self.type, _types.PointerType): + return self.int_from_bytes(self.value, self.type.width, False, self.endian) + elif isinstance(self.type, (_types.IntegerType, _types.EnumerationType)): + return self.int_from_bytes(self.value, self.type.width, bool(self.type.signed), self.endian) + raise Exception("Attempting to coerce non integral type to an integer") + + @staticmethod + def int_from_bytes(data:bytes, width:int, sign:bool, endian:Optional[Endianness]=None): + if width == 1: + code = "B" + elif width == 2: + code = "H" + elif width == 4: + code = "I" + elif width == 8: + code = "Q" else: - raise Exception("Could not convert to integer with width {}".format(self._type.width)) + raise Exception("Could not convert to integer with width {}".format(width)) - return struct.unpack(code, self._value)[0] + _endian = "<" if endian == Endianness.LittleEndian else ">" + if sign: + code = code.lower() + return struct.unpack(f"{_endian}{code}", data)[0] - @property - def type(self): - return self._type + def __float__(self): + if not isinstance(self.type, _types.FloatType): + raise Exception("Attempting to coerce non float type to a float") + endian = "<" if self.endian == Endianness.LittleEndian else ">" + if self.type.width == 2: + code = "e" + elif self.type.width == 4: + code = "f" + elif self.type.width == 8: + code = "d" + else: + raise Exception("Could not convert to float with width {}".format(self.type.width)) + return struct.unpack(f"{endian}{code}", self.value)[0] @property - def width(self): - return self._type.width + def int(self): + return int(self) @property - def address(self): - return self._address + def float(self): + return float(self) - @property - def value(self): - return self._value +# class StructuredDataView: +# @staticmethod +# def create(view:'BinaryView', structure_name:str, address:int, endian:Optional[Endianness]=None): +# s = view.get_type_by_name(structure_name) +# if s is None: +# raise Exception(f"Could not find structure with name: {structure_name}") - @property - def int(self): - return int(self) +# if s.type_class == TypeClass.NamedTypeReferenceClass: +# s = view.get_type_by_id(s.named_type_reference.id) +# if s.type_class != TypeClass.StructureTypeClass: +# raise Exception(f"{self.structure_name} is not a StructureTypeClass, got: {s.type_class}") - @property - def str(self): - return str(self) +# self._structure = s.structure +# return make_dataclass(f"{structure_name}_{address}_{endian}", fields) -class StructuredDataView: - """ - ``class StructuredDataView`` is a convenience class for reading structured binary data. +# class StructuredDataView: + # """ + # ``class StructuredDataView`` is a convenience class for reading structured binary data. - StructuredDataView can be instantiated as follows: + # StructuredDataView can be instantiated as follows: - >>> from binaryninja import * - >>> bv = BinaryViewType.get_view_of_file("/bin/ls") - >>> structure = "Elf64_Header" - >>> address = bv.start - >>> elf = StructuredDataView(bv, structure, address) - >>> + # >>> from binaryninja import * + # >>> bv = BinaryViewType.get_view_of_file("/bin/ls") + # >>> structure = "Elf64_Header" + # >>> address = bv.start + # >>> elf = StructuredDataView(bv, structure, address) + # >>> - Once instantiated, members can be accessed: + # Once instantiated, members can be accessed: - >>> print("{:x}".format(elf.machine)) - 003e - >>> + # >>> print("{:x}".format(elf.machine)) + # 003e + # >>> - """ - _structure = None - _structure_name = None - _address = 0 - _bv = None + # """ + # _structure = None + # _structure_name = None + # _address = 0 + # _bv = None - def __init__(self, bv:'BinaryView', structure_name:str, address:int, endian:Optional[Endianness]=None): - self._bv = bv - if endian is None: - if bv.arch is not None: - endian = bv.arch.endianness - else: - raise Exception("Can not instantiate StructuredDataView without specifying and Endianness") - self._structure_name = structure_name - self._address = address - self._members = OrderedDict() - self._endian = endian - self._lookup_structure() - self._define_members() + # def __init__(self, bv:'BinaryView', structure_name:str, address:int, endian:Optional[Endianness]=None): + # self._bv = bv + # if endian is None: + # if bv.arch is not None: + # endian = bv.arch.endianness + # else: + # raise Exception("Can not instantiate StructuredDataView without specifying and Endianness") + # self._structure_name = structure_name + # self._address = address + # self._members = OrderedDict() + # self._endian = endian + # self._lookup_structure() + # self._define_members() - def __repr__(self): - return "<StructuredDataView type:{self._structure_name} " + \ - "size:{self._structure.width:#x} address:{self._address:#x}>" + # def __repr__(self): + # return f"<StructuredDataView type:{self._structure_name} " + \ + # f"size:{self._structure.width:#x} address:{self._address:#x}>" - def __len__(self): - assert self._structure is not None, "self._structure is None" - return self._structure.width + # def __len__(self): + # assert self._structure is not None, "self._structure is None" + # return self._structure.width - def __getattr__(self, key): - m = self._members.get(key, None) - if m is None: - return self.__getattribute__(key) + # def __getattr__(self, key): + # m = self._members.get(key, None) + # if m is None: + # return self.__getattribute__(key) - return self[key] + # return self[key] - def __getitem__(self, key): - m = self._members.get(key, None) - if m is None: - return m + # def __getitem__(self, key): + # m = self._members.get(key, None) + # if m is None: + # return m - ty = m.type - offset = m.offset - width = ty.width + # ty = m.type + # offset = m.offset + # width = ty.width - value = self.view.read(self._address + offset, width) - return StructuredDataValue(ty, self._address + offset, value, self._endian) + # value = self.view.read(self._address + offset, width) + # return StructuredDataValue(ty, value, self._endian) - @property - def view(self) -> 'BinaryView': - assert self._bv is not None - return self._bv + # @property + # def view(self) -> 'BinaryView': + # assert self._bv is not None + # return self._bv - @property - def structure(self) -> '_types.Structure': - assert self._structure is not None - return self._structure + # @property + # def structure(self) -> '_types.Structure': + # assert self._structure is not None + # return self._structure - def __str__(self): - rv = "struct {name} 0x{addr:x} {{\n".format(name=self._structure_name, addr=self._address) - for k in self._members: - m = self._members[k] + # def __str__(self): + # rv = "struct {name} 0x{addr:x} {{\n".format(name=self._structure_name, addr=self._address) + # for k in self._members: + # m = self._members[k] - ty = m.type - offset = m.offset + # ty = m.type + # offset = m.offset - formatted_offset = "{:=+x}".format(offset) - formatted_type = "{:s} {:s}".format(str(ty), k) + # formatted_offset = "{:=+x}".format(offset) + # formatted_type = "{:s} {:s}".format(str(ty), k) - value = self[k] - assert value is not None - if value.width in (1, 2, 4, 8): - formatted_value = str.zfill("{:x}".format(value.int), value.width * 2) - else: - formatted_value = str(value) + # value = self[k] + # assert value is not None + # if value.width in (1, 2, 4, 8): + # formatted_value = str.zfill("{:x}".format(value.int), value.width * 2) + # else: + # formatted_value = str(value) - rv += "\t{:>6s} {:40s} = {:30s}\n".format(formatted_offset, formatted_type, formatted_value) + # rv += "\t{:>6s} {:40s} = {:30s}\n".format(formatted_offset, formatted_type, formatted_value) - rv += "}\n" + # rv += "}\n" - return rv + # return rv - def _lookup_structure(self): - s = self.view.get_type_by_name(self._structure_name) - if s is None: - raise Exception(f"Could not find structure with name: {self._structure_name}") + # def _lookup_structure(self): + # s = self.view.get_type_by_name(self._structure_name) + # if s is None: + # raise Exception(f"Could not find structure with name: {self._structure_name}") - if s.type_class != TypeClass.StructureTypeClass: - raise Exception(f"{self._structure_name} is not a StructureTypeClass, got: {s.type_class}") + # if s.type_class != TypeClass.StructureTypeClass: + # raise Exception(f"{self._structure_name} is not a StructureTypeClass, got: {s.type_class}") - self._structure = s.structure + # self._structure = s.structure - def _define_members(self): - for m in self.structure.members: - self._members[m.name] = m + # def _define_members(self): + # for m in self.structure.members: + # self._members[m.name] = m @dataclass(frozen=True) @@ -7450,61 +7486,123 @@ class CoreDataVariable: auto_discovered:bool +@dataclass class DataVariable: - def __init__(self, var:CoreDataVariable, view:'BinaryView'): - self._var = var - self._view = view + core_data_var:CoreDataVariable + view:'BinaryView' @classmethod def from_core_struct(cls, var:core.BNDataVariable, view:'BinaryView'): - var_type = _types.Type(core.BNNewTypeReference(var.type), platform=view.platform, + var_type = _types.Type.create(core.BNNewTypeReference(var.type), platform=view.platform, confidence=var.typeConfidence) return cls(CoreDataVariable(var.address, var_type, var.autoDiscovered), view) @property def data_refs_from(self) -> Optional[Generator[int, None, None]]: """data cross references from this data variable (read-only)""" - return self._view.get_data_refs_from(self.address, max(1, len(self))) + return self.view.get_data_refs_from(self.address, max(1, len(self))) @property def data_refs(self) -> Optional[Generator[int, None, None]]: """data cross references to this data variable (read-only)""" - return self._view.get_data_refs(self.address, max(1, len(self))) + return self.view.get_data_refs(self.address, max(1, len(self))) @property def code_refs(self) -> Generator['ReferenceSource', None, None]: """code references to this data variable (read-only)""" - return self._view.get_code_refs(self.address, max(1, len(self))) + return self.view.get_code_refs(self.address, max(1, len(self))) def __len__(self): - return len(self._var.type) + return len(self.core_data_var.type) def __repr__(self): return f"<var {self.address:#x}: {self.type}>" @property def address(self) -> int: - return self._var.address + return self.core_data_var.address + + def _value_helper(self, t:'_types.Type', data:bytes): + sdv = StructuredDataValue(t, data, self.view.endianness) + if isinstance(t, (_types.VoidType, _types.FunctionType)): #, _types.VarArgsType, _types.ValueType)): + return None + elif isinstance(t, _types.BoolType): + return bool(sdv) + elif isinstance(t, (_types.IntegerType, _types.PointerType)): + return int(sdv) + elif isinstance(t, _types.FloatType): + return float(sdv) + elif isinstance(t, _types.WideCharType): + return data.decode("utf-8") + elif isinstance(t, _types.StructureType): + result = {} + for member in t.members: + member_data = data[member.offset: member.offset+member.type.width] + result[member.name] = self._value_helper(member.type, member_data) + return result + elif isinstance(t, _types.EnumerationType): + value = int(sdv) + for member in t.members: + if int(member) == value: + return member + return value + elif isinstance(t, _types.ArrayType): + result = [] + if t.element_type is None: + raise ValueError("Can not get value for Array type with no element type") + for i in range(t.count): + offset = i * t.element_type.width + element_data = data[offset: offset + t.element_type.width] + result.append(self._value_helper(t.element_type, element_data)) + return result + elif isinstance(t, _types.NamedTypeReference): + target = self.view.get_type_by_id(t.id) + assert target is not None + return self._value_helper(target, data) + assert False, f"Unhandled `Type` {type(t)}" + + @property + def value(self) -> Any: + data = self.view.read(self.address, self.type.width) + if len(data) != self.type.width: + raise Exception(f"Failed to read bytes at address {self.address} of width {self.type.width}") + return self._value_helper(self.type, data) + + + # elif t.type_class == TypeClass.StructureTypeClass: + + # elif t.type_class == TypeClass.EnumerationTypeClass: + + # elif t.type_class == TypeClass.PointerTypeClass: + + # elif t.type_class == TypeClass.ArrayTypeClass: + + # elif t.type_class == TypeClass.FunctionTypeClass: + + # elif t.type_class == TypeClass.VarArgsTypeClass: + + # elif t.type_class == TypeClass.ValueTypeClass: + + # elif t.type_class == TypeClass.NamedTypeReferenceClass: + + # elif t.type_class == TypeClass.WideCharTypeClass: + @property def type(self) -> '_types.Type': - return self._var.type + return self.core_data_var.type @type.setter def type(self, value:Optional['_types.Type']) -> None: # type: ignore - self._view.define_user_data_var(self.address, value) + self.view.define_user_data_var(self.address, value) if value is None: - self._var = CoreDataVariable(self.address, _types.Type.void(), False) + self.core_data_var = CoreDataVariable(self.address, _types.VoidType.create(), False) else: - self._var = CoreDataVariable(self.address, value, False) + self.core_data_var = CoreDataVariable(self.address, value, False) @property def auto_discovered(self) -> bool: - return self._var.auto_discovered - - @property - def view(self) -> BinaryView: - return self._view + return self.core_data_var.auto_discovered @view.setter def view(self, value): @@ -7512,7 +7610,7 @@ class DataVariable: @property def symbol(self) -> Optional['_types.Symbol']: - return self._view.get_symbol_at(self.address) + return self.view.get_symbol_at(self.address) @symbol.setter def symbol(self, value:Optional[Union[str, '_types.Symbol']]) -> None: # type: ignore diff --git a/python/databuffer.py b/python/databuffer.py index bb6a8ca5..ef8fc483 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -35,7 +35,8 @@ class DataBuffer: self.handle = core.BNCreateDataBuffer(contents, len(contents)) def __del__(self): - core.BNFreeDataBuffer(self.handle) + if core is not None: + core.BNFreeDataBuffer(self.handle) def __len__(self): return int(core.BNGetDataBufferLength(self.handle)) diff --git a/python/datarender.py b/python/datarender.py index c44e444f..6a9982e9 100644 --- a/python/datarender.py +++ b/python/datarender.py @@ -31,6 +31,7 @@ from . import enums from . import log from . import types from . import highlight +from . import types class TypeContext: @@ -95,8 +96,7 @@ class DataRenderer: @staticmethod def is_type_of_struct_name(t, name, context): return (t.type_class == enums.TypeClass.StructureTypeClass and len(context) > 0 - and context[-1].type.type_class == enums.TypeClass.NamedTypeReferenceClass and - context[-1].type.named_type_reference.name == name) + and isinstance(context[-1].type, types.NamedTypeReferenceType) and context[-1].type.name == name) def register_type_specific(self): core.BNRegisterTypeSpecificDataRenderer(core.BNGetDataRendererContainer(), self.handle) @@ -116,10 +116,10 @@ class DataRenderer: try: file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) view = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) - type = types.Type(handle=core.BNNewTypeReference(type)) + type = types.Type.create(handle=core.BNNewTypeReference(type)) pycontext = [] for i in range(0, ctxCount): - pycontext.append(TypeContext(types.Type(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.log_error(traceback.format_exc()) @@ -129,12 +129,12 @@ class DataRenderer: try: file_metadata = filemetadata.FileMetadata(handle=core.BNGetFileForView(view)) view = binaryview.BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view)) - type = types.Type(handle=core.BNNewTypeReference(type)) + type = types.Type.create(handle=core.BNNewTypeReference(type)) prefixTokens = function.InstructionTextToken._from_core_struct(prefix, prefixCount) pycontext = [] for i in range(ctxCount): - pycontext.append(TypeContext(types.Type(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) diff --git a/python/demangle.py b/python/demangle.py index 105ee889..cff2937e 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -70,7 +70,7 @@ def demangle_ms(arch, mangled_name, options = False): for i in range(outSize.value): names.append(outName[i].decode('utf8')) # type: ignore core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) - return (types.Type(handle), names) + return (types.Type.create(core.BNNewTypeReference(handle)), names) return (None, mangled_name) @@ -97,7 +97,7 @@ def demangle_gnu3(arch, mangled_name, options = None): core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) if not handle: return (None, names) - return (types.Type(handle), names) + return (types.Type.create(core.BNNewTypeReference(handle)), names) return (None, mangled_name) diff --git a/python/examples/triage/imports.py b/python/examples/triage/imports.py index 09477bff..55b09c6d 100644 --- a/python/examples/triage/imports.py +++ b/python/examples/triage/imports.py @@ -147,7 +147,7 @@ def find_dynamically_linked_funcs(bv): output_var = call.output.vars_written[0] symbol_name = bv.get_ascii_string_at(symbol_name_addr.value).value #Add confidence to both the args and the return of zero - symbol_type = Type.pointer(bv.arch, bv.parse_type_string("void foo()")[0]) + symbol_type = Type.pointer(bv.parse_type_string("void foo()")[0], arch=bv.arch) if len(symbol_name) == 0: continue diff --git a/python/filemetadata.py b/python/filemetadata.py index 06e7324a..40d937a4 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -86,7 +86,8 @@ class SaveSettings: self.handle = handle def __del__(self): - core.BNFreeSaveSettings(self.handle) + if core is not None: + core.BNFreeSaveSettings(self.handle) def is_option_set(self, option:SaveOption) -> bool: if isinstance(option, str): diff --git a/python/flowgraph.py b/python/flowgraph.py index 0a0faae9..2fe4545a 100644 --- a/python/flowgraph.py +++ b/python/flowgraph.py @@ -162,8 +162,8 @@ class FlowGraphNode: func = function.Function(view, func_handle) if core.BNIsLowLevelILBasicBlock(block): - block = lowlevelil.LowLevelILBasicBlock(view, block, - lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) + block = lowlevelil.LowLevelILBasicBlock(block, + lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func), view) elif core.BNIsMediumLevelILBasicBlock(block): mlil_func = mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func) block = mediumlevelil.MediumLevelILBasicBlock(block, mlil_func, view) @@ -338,6 +338,8 @@ class FlowGraphLayoutRequest: self.handle = core.BNStartFlowGraphLayout(graph.handle, None, self._cb) def __del__(self): + if core is None: + return self.abort() core.BNFreeFlowGraphLayoutRequest(self.handle) @@ -411,7 +413,8 @@ class FlowGraph: self.handle = handle def __del__(self): - core.BNFreeFlowGraph(self.handle) + if core is not None: + core.BNFreeFlowGraph(self.handle) def __repr__(self): function = self.function diff --git a/python/function.py b/python/function.py index 3aba76f2..74717595 100644 --- a/python/function.py +++ b/python/function.py @@ -88,7 +88,8 @@ class DisassemblySettings: self.handle = handle def __del__(self): - core.BNFreeDisassemblySettings(self.handle) + if core is not None: + core.BNFreeDisassemblySettings(self.handle) @property def width(self) -> int: @@ -842,7 +843,7 @@ class Function: Function type object, can be set with either a string representing the function prototype (`str(function)` shows examples) or a :py:class:`Type` object """ - return types.Type(core.BNGetFunctionType(self.handle), platform = self.platform) + return types.Type.create(core.BNGetFunctionType(self.handle), platform = self.platform) @function_type.setter def function_type(self, value:'types.Type') -> None: @@ -961,7 +962,7 @@ class Function: result = core.BNGetFunctionReturnType(self.handle) if not result.type: return None - return types.Type(result.type, platform = self.platform, confidence = result.confidence) + return types.Type.create(core.BNNewTypeReference(result.type), platform = self.platform, confidence = result.confidence) @return_type.setter def return_type(self, value:'types.Type') -> None: @@ -1941,7 +1942,7 @@ class Function: assert refs is not None, "core.BNGetStackVariablesReferencedByInstruction returned None" result = [] for i in range(0, count.value): - var_type = types.Type(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence) + var_type = types.Type.create(core.BNNewTypeReference(refs[i].type), platform = self.platform, confidence = refs[i].typeConfidence) var = variable.Variable.from_identifier(self, refs[i].varIdentifier) result.append(variable.StackVariableReference(refs[i].sourceOperand, var_type, refs[i].name, var, refs[i].referencedOffset, refs[i].size)) @@ -2503,15 +2504,11 @@ class Function: core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) def create_auto_stack_var(self, offset:int, var_type:'types.Type', name:str) -> None: - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNCreateAutoStackVariable(self.handle, offset, tc, name) def create_user_stack_var(self, offset:int, var_type:'types.Type', name:str) -> None: - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNCreateUserStackVariable(self.handle, offset, tc, name) def delete_auto_stack_var(self, offset:int) -> None: @@ -2522,16 +2519,12 @@ class Function: def create_auto_var(self, var:'variable.Variable', var_type:'types.Type', name:str, ignore_disjoint_uses:bool=False) -> None: - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNCreateAutoVariable(self.handle, var.to_BNVariable(), tc, name, ignore_disjoint_uses) def create_user_var(self, var:'variable.Variable', var_type:'types.Type', name:str, ignore_disjoint_uses:bool=False) -> None: - tc = core.BNTypeWithConfidence() - tc.type = var_type.handle - tc.confidence = var_type.confidence + tc = var_type.to_core_struct() core.BNCreateUserVariable(self.handle, var.to_BNVariable(), tc, name, ignore_disjoint_uses) def delete_auto_var(self, var:'variable.Variable') -> None: @@ -2628,9 +2621,7 @@ class Function: if adjust_type is None: tc = None else: - tc = core.BNTypeWithConfidence() - tc.type = adjust_type.handle - tc.confidence = adjust_type.confidence + tc = adjust_type.to_core_struct() core.BNSetUserCallTypeAdjustment(self.handle, arch.handle, addr, tc) def set_call_stack_adjustment(self, addr:int, adjust:Union[int, 'types.SizeWithConfidence'], @@ -2683,7 +2674,7 @@ class Function: if not result.type: return None platform = self.platform - return types.Type(result.type, platform = platform, confidence = result.confidence) + return types.Type.create(core.BNNewTypeReference(result.type), platform = platform, confidence = result.confidence) def get_call_stack_adjustment(self, addr:int, arch:Optional['architecture.Architecture']=None) -> 'types.SizeWithConfidence': if arch is None: @@ -3200,7 +3191,8 @@ class DisassemblyTextRenderer: self.handle = handle def __del__(self): - core.BNFreeDisassemblyTextRenderer(self.handle) + if core is not None: + core.BNFreeDisassemblyTextRenderer(self.handle) @property def function(self) -> 'Function': diff --git a/python/highlevelil.py b/python/highlevelil.py index 073fbfda..2aadee13 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -401,7 +401,7 @@ class HighLevelILInstruction: platform = None if self.function.source_function: platform = self.function.source_function.platform - return types.Type(result.type, platform = platform, confidence = result.confidence) + return types.Type.create(core.BNNewTypeReference(result.type), platform = platform, confidence = result.confidence) return None def get_possible_values(self, options:List[DataFlowQueryOption]=[]) -> 'variable.PossibleValueSet': diff --git a/python/lineardisassembly.py b/python/lineardisassembly.py index 3b539af4..c199e2f7 100644 --- a/python/lineardisassembly.py +++ b/python/lineardisassembly.py @@ -132,7 +132,8 @@ class LinearViewObject: self._parent = parent def __del__(self): - core.BNFreeLinearViewObject(self.handle) + if core is not None: + core.BNFreeLinearViewObject(self.handle) def __repr__(self): return "<LinearViewObject: " + str(self) + ">" @@ -337,7 +338,8 @@ class LinearViewCursor: self.handle = core.BNCreateLinearViewCursor(root_object.handle) def __del__(self): - core.BNFreeLinearViewCursor(self.handle) + if core is not None: + core.BNFreeLinearViewCursor(self.handle) def __repr__(self): return "<LinearViewCursor: " + str(self.current_object) + ">" diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 27f165d2..fc685533 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -340,7 +340,7 @@ class MediumLevelILInstruction: platform = None if self.function.source_function: platform = self.function.source_function.platform - return types.Type(result.type, platform = platform, confidence = result.confidence) + return types.Type.create(core.BNNewTypeReference(result.type), platform = platform, confidence = result.confidence) return None def get_possible_values(self, options:List[DataFlowQueryOption]=[]) -> variable.PossibleValueSet: diff --git a/python/platform.py b/python/platform.py index 2dacf7a6..21055fb3 100644 --- a/python/platform.py +++ b/python/platform.py @@ -251,7 +251,7 @@ class Platform(metaclass=_PlatformMetaClass): result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -264,7 +264,7 @@ class Platform(metaclass=_PlatformMetaClass): result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -277,7 +277,7 @@ class Platform(metaclass=_PlatformMetaClass): result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -290,7 +290,7 @@ class Platform(metaclass=_PlatformMetaClass): result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(call_list[i].name) - t = types.Type(core.BNNewTypeReference(call_list[i].type), platform = self) + t = types.Type.create(core.BNNewTypeReference(call_list[i].type), platform = self) result[call_list[i].number] = (name, t) core.BNFreeSystemCallList(call_list, count.value) return result @@ -354,21 +354,21 @@ class Platform(metaclass=_PlatformMetaClass): obj = core.BNGetPlatformTypeByName(self.handle, name) if not obj: return None - return types.Type(obj, platform = self) + return types.Type.create(core.BNNewTypeReference(obj), platform = self) def get_variable_by_name(self, name): name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformVariableByName(self.handle, name) if not obj: return None - return types.Type(obj, platform = self) + return types.Type.create(core.BNNewTypeReference(obj), platform = self) def get_function_by_name(self, name, exactMatch=False): name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformFunctionByName(self.handle, name, exactMatch) if not obj: return None - return types.Type(obj, platform = self) + return types.Type.create(core.BNNewTypeReference(obj), platform = self) def get_system_call_name(self, number): return core.BNGetPlatformSystemCallName(self.handle, number) @@ -377,7 +377,7 @@ class Platform(metaclass=_PlatformMetaClass): obj = core.BNGetPlatformSystemCallType(self.handle, number) if not obj: return None - return types.Type(obj, platform = self) + return types.Type.create(core.BNNewTypeReference(obj), platform = self) def generate_auto_platform_type_id(self, name): name = types.QualifiedName(name)._get_core_struct() @@ -431,13 +431,13 @@ class Platform(metaclass=_PlatformMetaClass): 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(core.BNNewTypeReference(parse.types[i].type), platform = self) + type_dict[name] = types.Type.create(core.BNNewTypeReference(parse.types[i].type), platform = self) for i in range(0, parse.variableCount): name = types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + variables[name] = types.Type.create(core.BNNewTypeReference(parse.variables[i].type), platform = self) for i in range(0, parse.functionCount): name = types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + functions[name] = types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform = self) core.BNFreeTypeParserResult(parse) return types.TypeParserResult(type_dict, variables, functions) @@ -481,13 +481,13 @@ class Platform(metaclass=_PlatformMetaClass): functions = {} for i in range(0, parse.typeCount): name = types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) + type_dict[name] = types.Type.create(core.BNNewTypeReference(parse.types[i].type), platform = self) for i in range(0, parse.variableCount): name = types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + variables[name] = types.Type.create(core.BNNewTypeReference(parse.variables[i].type), platform = self) for i in range(0, parse.functionCount): name = types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + functions[name] = types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform = self) core.BNFreeTypeParserResult(parse) return types.TypeParserResult(type_dict, variables, functions) diff --git a/python/plugin.py b/python/plugin.py index 2cbc6d0e..cf6ab0f9 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -585,7 +585,8 @@ class MainThreadAction: self.handle = handle def __del__(self): - core.BNFreeMainThreadAction(self.handle) + if core is not None: + core.BNFreeMainThreadAction(self.handle) def execute(self): core.BNExecuteMainThreadAction(self.handle) @@ -641,7 +642,8 @@ class BackgroundTask(metaclass=_BackgroundTaskMetaclass): self.handle = handle def __del__(self): - core.BNFreeBackgroundTask(self.handle) + if core is not None: + core.BNFreeBackgroundTask(self.handle) @property def progress(self): diff --git a/python/pluginmanager.py b/python/pluginmanager.py index aa68a4f3..0e5c4c97 100644 --- a/python/pluginmanager.py +++ b/python/pluginmanager.py @@ -37,7 +37,8 @@ class RepoPlugin: self.handle = core.handle_of_type(handle, core.BNRepoPlugin) def __del__(self): - core.BNFreePlugin(self.handle) + if core is not None: + core.BNFreePlugin(self.handle) def __repr__(self): return "<{} {}/{}>".format(self.path, "installed" if self.installed else "not-installed", "enabled" if self.enabled else "disabled") @@ -263,7 +264,8 @@ class Repository: self.handle = core.handle_of_type(handle, core.BNRepository) def __del__(self): - core.BNFreeRepository(self.handle) + if core is not None: + core.BNFreeRepository(self.handle) def __repr__(self): return "<{}>".format(self.path) diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index d3b2c23c..335d9af1 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -129,7 +129,8 @@ class ScriptingInstance: self.listeners = [] def __del__(self): - core.BNFreeScriptingInstance(self.handle) + if core is not None: + core.BNFreeScriptingInstance(self.handle) def _destroy_instance(self, ctxt): try: diff --git a/python/typelibrary.py b/python/typelibrary.py index 3dc3dbfa..e392557f 100644 --- a/python/typelibrary.py +++ b/python/typelibrary.py @@ -35,10 +35,11 @@ class TypeLibrary: self.handle = core.handle_of_type(handle, core.BNTypeLibrary) def __del__(self): - core.BNFreeTypeLibrary(self.handle) + if core is not None: + core.BNFreeTypeLibrary(self.handle) def __repr__(self): - return "<typelib '{}':{}>".format(self.name, self.arch.name) + return f"<typelib '{self.name}':{self.arch.name}>" @staticmethod def new(arch, name): @@ -263,7 +264,7 @@ class TypeLibrary: """ core.BNTypeLibraryRemoveMetadata(self.handle, key) - def add_named_object(self, name, t): + def add_named_object(self, name:'types.QualifiedName', type:'types.Type') -> None: """ `add_named_object` directly inserts a named object into the type library's object store. This is not done recursively, so care should be taken that types referring to other types @@ -279,11 +280,13 @@ class TypeLibrary: """ if not isinstance(name, types.QualifiedName): name = types.QualifiedName(name) - if not isinstance(t, types.Type): - raise ValueError("t must be a Type") - core.BNAddTypeLibraryNamedObject(self.handle, name._get_core_struct(), t.handle) + if isinstance(type, types.MutableType): + type = type.immutable_copy() + if not isinstance(type, types.Type): + raise ValueError("type must be a Type") + core.BNAddTypeLibraryNamedObject(self.handle, name._get_core_struct(), type.handle) - def add_named_type(self, name, t): + def add_named_type(self, name:'types.QualifiedName', type:'types.Type') -> None: """ `add_named_type` directly inserts a named object into the type library's object store. This is not done recursively, so care should be taken that types referring to other types @@ -299,9 +302,11 @@ class TypeLibrary: """ if not isinstance(name, types.QualifiedName): name = types.QualifiedName(name) - if not isinstance(t, types.Type): - raise ValueError("t must be a Type") - core.BNAddTypeLibraryNamedType(self.handle, name._get_core_struct(), t.handle) + if isinstance(type, types.MutableType): + type = type.immutable_copy() + if not isinstance(type, types.Type): + raise ValueError("parameter type must be a Type") + core.BNAddTypeLibraryNamedType(self.handle, name._get_core_struct(), type.handle) def get_named_object(self, name): """ @@ -317,7 +322,7 @@ class TypeLibrary: t = core.BNGetTypeLibraryNamedObject(self.handle, name._get_core_struct()) if t is None: return None - return types.Type(t) + return types.Type.create(t) def get_named_type(self, name): """ @@ -333,7 +338,7 @@ class TypeLibrary: t = core.BNGetTypeLibraryNamedType(self.handle, name._get_core_struct()) if t is None: return None - return types.Type(t) + return types.Type.create(t) @property def named_objects(self): @@ -346,7 +351,7 @@ class TypeLibrary: assert named_types is not None, "core.BNGetTypeLibraryNamedObjects returned None" for i in range(0, count.value): name = types.QualifiedName._from_core_struct(named_types[i].name) - result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) + result[name] = types.Type.create(core.BNNewTypeReference(named_types[i].type)) core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) return result @@ -361,7 +366,7 @@ class TypeLibrary: assert named_types is not None, "core.BNGetTypeLibraryNamedTypes returned None" for i in range(0, count.value): name = types.QualifiedName._from_core_struct(named_types[i].name) - result[name] = types.Type(core.BNNewTypeReference(named_types[i].type)) + result[name] = types.Type.create(core.BNNewTypeReference(named_types[i].type)) core.BNFreeQualifiedNameAndTypeArray(named_types, count.value) return result diff --git a/python/types.py b/python/types.py index d3f6294d..ddaa5384 100644 --- a/python/types.py +++ b/python/types.py @@ -20,19 +20,43 @@ import ctypes from typing import Generator, List, Union, Mapping, Tuple, Optional -from dataclasses import dataclass +from dataclasses import dataclass, field +import uuid +from abc import ABC, abstractmethod # Binary Ninja components from . import _binaryninjacore as core -from .enums import SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, StructureType, ReferenceType, VariableSourceType, TypeReferenceType +from .enums import (StructureVariant, SymbolType, SymbolBinding, TypeClass, + NamedTypeReferenceClass, ReferenceType, VariableSourceType, TypeReferenceType, MemberAccess, MemberScope) from . import callingconvention -from . import function +from . import function as _function from . import variable from . import architecture from . import types +from . import binaryview +from . import platform as _platform from . import log +from . import typelibrary QualifiedNameType = Union[List[str], str, 'QualifiedName', List[bytes]] +BoolWithConfidenceType = Union[bool, 'BoolWithConfidence'] +SizeWithConfidenceType = Union[int, 'SizeWithConfidence'] +OffsetWithConfidenceType = Union[int, 'OffsetWithConfidence'] +ParamsType = Union[List['Type'], List['FunctionParameter'], List[Tuple['Type', str]]] +MembersType = Union[List['StructureMember'], List[Tuple['Type', str]]] +EnumMembersType = Union[List[Tuple[str,int]], List[str], List['EnumerationMember']] +SomeType = Union['MutableType', 'Type'] +TypeContainer = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary'] +# The following are needed to prevent the type checker from getting +# confused as we have member functions in `Type` named the same thing +_int = int +_bool = bool +MemberName = str +MemberIndex = int +MemberOffset = int + +class TypeCreateException(ValueError): + pass class QualifiedName: def __init__(self, name:QualifiedNameType=[]): @@ -139,13 +163,13 @@ class QualifiedName: self._name = value +@dataclass(frozen=True) class TypeReferenceSource: - def __init__(self, name, offset, ref_type): - self._name = name - self._offset = offset - self._ref_type = ref_type + name:QualifiedName + offset:int + ref_type:TypeReferenceType - def __str__(self): + def __repr__(self): if self.ref_type == TypeReferenceType.DirectTypeReferenceType: s = 'direct' elif self.ref_type == TypeReferenceType.IndirectTypeReferenceType: @@ -154,70 +178,6 @@ class TypeReferenceSource: s = 'unknown' return '<type %s, offset 0x%x, %s>' % (self.name, self.offset, s) - def __repr__(self): - return repr(str(self)) - - @property - def name(self): - return self._name - - @property - def offset(self): - return self._offset - - @property - def ref_type(self): - return self._ref_type - - def __eq__(self, other): - if isinstance(other, self.__class__): - return self.name == other.name and self.offset == other.offset and self.ref_type == other.ref_type - return NotImplemented - - def __ne__(self, other): - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __lt__(self, other): - if isinstance(other, self.__class__): - if self.name < other.name: - return True - elif self.name > other.name: - return False - elif self.offset < other.offset: - return True - elif self.offset > other.offset: - return False - return self.ref_type < other.ref_type - return NotImplemented - - def __gt__(self, other): - if isinstance(other, self.__class__): - if self.name > other.name: - return True - elif self.name < other.name: - return False - elif self.offset > other.offset: - return True - elif self.offset < other.offset: - return False - return self.ref_type > other.ref_type - return NotImplemented - - def __cmp__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - - if self == other: - return 0 - elif self < other: - return -1 - return 1 - - def __hash__(self): - return hash(str(self)) - class NameSpace(QualifiedName): def __str__(self): @@ -278,7 +238,8 @@ class Symbol: self.handle = _handle def __del__(self): - core.BNFreeSymbol(self.handle) + if core is not None: + core.BNFreeSymbol(self.handle) def __repr__(self): return "<%s: \"%s\" @ %#x>" % (self.type, self.full_name, self.address) @@ -348,16 +309,172 @@ class Symbol: def auto(self): return core.BNIsSymbolAutoDefined(self.handle) -@dataclass(frozen=True) + +@dataclass class FunctionParameter: - type:'types.Type' + type:SomeType name:str = "" location:Optional['variable.VariableNameAndType'] = None def __repr__(self): if (self.location is not None) and (self.location.name != self.name): - return "%s %s%s @ %s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name(), self.location.name) - return "%s %s%s" % (self.type.get_string_before_name(), self.name, self.type.get_string_after_name()) + return "%s %s%s @ %s" % (self.type.immutable_copy().get_string_before_name(), self.name, self.type.immutable_copy().get_string_after_name(), self.location.name) + return "%s %s%s" % (self.type.immutable_copy().get_string_before_name(), self.name, self.type.immutable_copy().get_string_after_name()) + + def immutable_copy(self) -> 'FunctionParameter': + return FunctionParameter(self.type.immutable_copy(), self.name, self.location) + + def mutable_copy(self) -> 'FunctionParameter': + return FunctionParameter(self.type.mutable_copy(), self.name, self.location) + + +@dataclass(frozen=True) +class OffsetWithConfidence: + value:int + confidence:int=core.max_confidence + + def __int__(self): + return self.value + + def to_core_struct(self) -> core.BNOffsetWithConfidence: + result = core.BNOffsetWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct:core.BNOffsetWithConfidence) -> 'OffsetWithConfidence': + return cls(core_struct.value, core_struct.confidence) + + +@dataclass(frozen=True) +class BoolWithConfidence: + value:bool + confidence:int=core.max_confidence + + def __bool__(self): + return self.value + + def to_core_struct(self) -> core.BNBoolWithConfidence: + result = core.BNBoolWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct:core.BNBoolWithConfidence) -> 'BoolWithConfidence': + return cls(core_struct.value, core_struct.confidence) + + +@dataclass(frozen=True) +class MemberAccessWithConfidence: + value:MemberAccess + confidence:int=core.max_confidence + + def to_core_struct(self) -> core.BNMemberAccessWithConfidence: + result = core.BNMemberAccessWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct:core.BNMemberAccessWithConfidence) -> 'MemberAccessWithConfidence': + return cls(core_struct.value, core_struct.confidence) + + +@dataclass(frozen=True) +class MemberScopeWithConfidence: + value:MemberScope + confidence:int=core.max_confidence + + def to_core_struct(self) -> core.BNMemberScopeWithConfidence: + result = core.BNMemberScopeWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct:core.BNMemberScopeWithConfidence) -> 'MemberScopeWithConfidence': + return cls(core_struct.value, core_struct.confidence) + + +@dataclass(frozen=True) +class SizeWithConfidence: + value:int + confidence:int=core.max_confidence + + def __int__(self): + return self.value + + def to_core_struct(self) -> core.BNSizeWithConfidence: + result = core.BNSizeWithConfidence() + result.value = self.value + result.confidence = self.confidence + return result + + @classmethod + def from_core_struct(cls, core_struct:core.BNSizeWithConfidence) -> 'SizeWithConfidence': + return cls(core_struct.value, core_struct.confidence) + + +class _TypeBuilder: + def __init__(self, handle, **kwargs): + assert isinstance(handle.contents, core.BNTypeBuilder), "Attempting to create mutable Type" + self.handle = handle + core.BNTypeBuilderSetConst(self.handle, kwargs.get("const", BoolWithConfidence(False)).to_core_struct()) + core.BNTypeBuilderSetVolatile(self.handle, kwargs.get("volatile", BoolWithConfidence(False)).to_core_struct()) + core.BNSetFunctionTypeBuilderCanReturn(self.handle, kwargs.get("can_return", BoolWithConfidence(False).to_core_struct())) + core.BNTypeBuilderSetMemberScope(self.handle, kwargs.get("member_scope", MemberScopeWithConfidence(MemberScope.NoScope).to_core_struct())) + core.BNTypeBuilderSetMemberAccess(self.handle, kwargs.get("member_access", MemberAccessWithConfidence(MemberAccess.NoAccess).to_core_struct())) + + def finalize(self): + type_handle = core.BNFinalizeTypeBuilder(self.handle) + assert type_handle is not None, "core.BNFinalizeTypeBuilder returned None" + return type_handle + + @property + def const(self) -> BoolWithConfidence: + """Whether type is const (read/write)""" + result = core.BNIsTypeBuilderConst(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + @const.setter + def const(self, value:BoolWithConfidence) -> None: + core.BNTypeBuilderSetConst(self.handle, value.to_core_struct()) + + @property + def volatile(self) -> BoolWithConfidence: + """Whether type is volatile (read/write)""" + result = core.BNIsTypeBuilderVolatile(self.handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + @volatile.setter + def volatile(self, value:BoolWithConfidence) -> None: + core.BNTypeBuilderSetVolatile(self.handle, value.to_core_struct()) + + @property + def can_return(self): + core.BNFunctionTypeBuilderCanReturn(self.handle) + + @can_return.setter + def can_return(self, value): + core.BNSetFunctionTypeBuilderCanReturn(self.handle, value) + + @property + def member_scope(self): + core.BNTypeBuilderGetMemberScope(self.handle) + + @member_scope.setter + def member_scope(self, value): + core.BNTypeBuilderSetMemberScope(self.handle, value) + + @property + def member_access(self): + core.BNTypeBuilderGetMemberAccess(self.handle) + + @member_access.setter + def member_access(self, value): + core.BNTypeBuilderSetMemberAccess(self.handle, value) class Type: @@ -372,33 +489,39 @@ class Type: :py:meth:`parse_types_from_source_file <binaryninja.platform.Platform.parse_types_from_source_file>` """ - def __init__(self, handle, platform = None, confidence = core.max_confidence): + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + assert isinstance(handle.contents, core.BNType), "Attempting to create mutable Type" self._handle = handle - self._mutable = isinstance(handle.contents, core.BNTypeBuilder) self._confidence = confidence self._platform = platform + @classmethod + def create(cls, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + type_class = TypeClass(core.BNGetTypeClass(handle)) + try: + return Types[type_class](handle, platform, confidence) + except TypeError: + assert False, f"{str(type_class)}" + def __del__(self): - if self._mutable: - core.BNFreeTypeBuilder(self._handle) - else: + if core is not None: core.BNFreeType(self._handle) def __repr__(self): if self._confidence < core.max_confidence: - return "<type: %s, %d%% confidence>" % (str(self), (self._confidence * 100) // core.max_confidence) - return "<type: %s>" % str(self) + return f"<type: {self}, {self._confidence * 100 // core.max_confidence}% confidence>" + return f"<type: {self}>" def __str__(self): platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - return core.BNGetTypeBuilderString(self._handle, platform) - name = self.registered_name - if (name is not None) and (self.type_class != TypeClass.StructureTypeClass) and (self.type_class != TypeClass.EnumerationTypeClass): - return self.get_string_before_name() + " " + str(name.name) + self.get_string_after_name() return core.BNGetTypeString(self._handle, platform) + name = None + if isinstance(self, RegisteredNameType): + name = self.registered_name + if (name is not None) and (not isinstance(self, (StructureType, EnumerationType))): + return self.get_string_before_name() + " " + str(name.name) + self.get_string_after_name() def __len__(self): return self.width @@ -415,711 +538,606 @@ class Type: @property def handle(self): - if self._mutable: - # First use of a mutable Type makes it immutable - finalized = core.BNFinalizeTypeBuilder(self._handle) - core.BNFreeTypeBuilder(self._handle) - self._handle = finalized - self._mutable = False return self._handle @property - def type_class(self): + def type_class(self) -> TypeClass: """Type class (read-only)""" - if self._mutable: - return TypeClass(core.BNGetTypeBuilderClass(self._handle)) return TypeClass(core.BNGetTypeClass(self._handle)) @property - def width(self): + def width(self) -> int: """Type width (read-only)""" - if self._mutable: - return core.BNGetTypeBuilderWidth(self._handle) return core.BNGetTypeWidth(self._handle) @property - def alignment(self): + def alignment(self) -> int: """Type alignment (read-only)""" - if self._mutable: - return core.BNGetTypeBuilderAlignment(self._handle) return core.BNGetTypeAlignment(self._handle) @property - def signed(self): - """Whether type is signed (read-only)""" - if self._mutable: - result = core.BNIsTypeBuilderSigned(self._handle) - else: - result = core.BNIsTypeSigned(self._handle) - return BoolWithConfidence(result.value, confidence = result.confidence) - - @property - def const(self): - """Whether type is const (read/write)""" - if self._mutable: - result = core.BNIsTypeBuilderConst(self._handle) - else: - result = core.BNIsTypeConst(self._handle) - return BoolWithConfidence(result.value, confidence = result.confidence) - - @const.setter - def const(self, value): - if not self._mutable: - raise AttributeError("Finalized Type object is immutable, use mutable_copy()") - bc = core.BNBoolWithConfidence() - bc.value = bool(value) - if hasattr(value, 'confidence'): - bc.confidence = value.confidence - else: - bc.confidence = core.max_confidence - core.BNTypeBuilderSetConst(self._handle, bc) - - @property - def volatile(self): - """Whether type is volatile (read/write)""" - if self._mutable: - result = core.BNIsTypeBuilderVolatile(self._handle) - else: - result = core.BNIsTypeVolatile(self._handle) - return BoolWithConfidence(result.value, confidence = result.confidence) - - @volatile.setter - def volatile(self, value): - if not self._mutable: - raise AttributeError("Finalized Type object is immutable, use mutable_copy()") - bc = core.BNBoolWithConfidence() - bc.value = bool(value) - if hasattr(value, 'confidence'): - bc.confidence = value.confidence - else: - bc.confidence = core.max_confidence - core.BNTypeBuilderSetVolatile(self._handle, bc) - - @property - def floating_point(self): - """Whether type is floating point (read-only)""" - if self._mutable: - return core.BNIsTypeBuilderFloatingPoint(self._handle) - return core.BNIsTypeFloatingPoint(self._handle) - - @property - def target(self): - """Target (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderChildType(self._handle) - else: - result = core.BNGetChildType(self._handle) - if not result.type: - return None - return Type(result.type, platform = self._platform, confidence = result.confidence) - - @property - def element_type(self): - """Target (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderChildType(self._handle) - else: - result = core.BNGetChildType(self._handle) - if not result.type: - return None - return Type(result.type, platform = self._platform, confidence = result.confidence) - - @property - def return_value(self): - """Return value (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderChildType(self._handle) - else: - result = core.BNGetChildType(self._handle) - if not result.type: - return None - return Type(result.type, platform = self._platform, confidence = result.confidence) - - @property - def calling_convention(self): - """Calling convention (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderCallingConvention(self._handle) - else: - result = core.BNGetTypeCallingConvention(self._handle) - if not result.convention: - return None - return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence) - - @property - def parameters(self): - """Type parameters list (read-only)""" - count = ctypes.c_ulonglong() - if self._mutable: - params = core.BNGetTypeBuilderParameters(self._handle, count) - assert params is not None, "core.BNGetTypeBuilderParameters returned None" - else: - params = core.BNGetTypeParameters(self._handle, count) - assert params is not None, "core.BNGetTypeParameters returned None" - result = [] - for i in range(0, count.value): - param_type = Type(core.BNNewTypeReference(params[i].type), platform = self._platform, confidence = params[i].typeConfidence) - if params[i].defaultLocation: - param_location = None - else: - name = params[i].name - if (params[i].location.type == VariableSourceType.RegisterVariableSourceType) and (self._platform is not None): - name = self._platform.arch.get_reg_name(params[i].location.storage) - elif params[i].location.type == VariableSourceType.StackVariableSourceType: - name = "arg_%x" % params[i].location.storage - param_location = variable.VariableNameAndType(params[i].location.type, params[i].location.index, - params[i].location.storage, name, param_type) - result.append(FunctionParameter(param_type, params[i].name, param_location)) - core.BNFreeTypeParameterList(params, count.value) - return result - - @property - def has_variable_arguments(self): - """Whether type has variable arguments (read-only)""" - if self._mutable: - result = core.BNTypeBuilderHasVariableArguments(self._handle) - else: - result = core.BNTypeHasVariableArguments(self._handle) - return BoolWithConfidence(result.value, confidence = result.confidence) - - @property - def can_return(self): - """Whether type can return""" - if self._mutable: - result = core.BNFunctionTypeBuilderCanReturn(self._handle) - else: - result = core.BNFunctionTypeCanReturn(self._handle) - return BoolWithConfidence(result.value, confidence = result.confidence) - - @can_return.setter - def can_return(self, value): - """Whether type can return (read-only)""" - if not self._mutable: - raise AttributeError("Finalized Type object is immutable, use mutable_copy()") - bc = core.BNBoolWithConfidence() - bc.value = bool(value) - if hasattr(value, 'confidence'): - bc.confidence = value.confidence - else: - bc.confidence = core.max_confidence - core.BNSetFunctionTypeBuilderCanReturn(self._handle, bc) - - @property - def structure(self): - """Structure of the type (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderStructure(self._handle) - else: - result = core.BNGetTypeStructure(self._handle) - if result is None: - return None - return Structure(result) - - @property - def enumeration(self): - """Type enumeration (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderEnumeration(self._handle) - else: - result = core.BNGetTypeEnumeration(self._handle) - if result is None: - return None - return Enumeration(result) - - @property - def named_type_reference(self): - """Reference to a named type (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderNamedTypeReference(self._handle) - else: - result = core.BNGetTypeNamedTypeReference(self._handle) - if result is None: - return None - return NamedTypeReference(handle = result) - - @property - def count(self): - """Type count (read-only)""" - if self._mutable: - return core.BNGetTypeBuilderElementCount(self._handle) - return core.BNGetTypeElementCount(self._handle) - - @property - def offset(self): + def offset(self) -> int: """Offset into structure (read-only)""" - if self._mutable: - return core.BNGetTypeBuilderOffset(self._handle) return core.BNGetTypeOffset(self._handle) @property - def stack_adjustment(self): - """Stack adjustment for function (read-only)""" - if self._mutable: - result = core.BNGetTypeBuilderStackAdjustment(self._handle) - else: - result = core.BNGetTypeStackAdjustment(self._handle) - return SizeWithConfidence(result.value, confidence = result.confidence) + def altname(self) -> str: + """Alternative name for the type object""" + return core.BNGetTypeAlternateName(self._handle) - @property - def registered_name(self): - """Name of type registered to binary view, if any (read-only)""" - if self._mutable: - return None - name = core.BNGetRegisteredTypeName(self._handle) - if not name: - return None - return NamedTypeReference(handle = name) + def to_core_struct(self) -> core.BNTypeWithConfidence: + type_conf = core.BNTypeWithConfidence() + type_conf.type = self.handle + type_conf.confidence = self.confidence + return type_conf - def get_string_before_name(self): + def get_string_before_name(self) -> str: platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - return core.BNGetTypeBuilderStringBeforeName(self._handle, platform) return core.BNGetTypeStringBeforeName(self._handle, platform) - def get_string_after_name(self): + def get_string_after_name(self) -> str: platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - return core.BNGetTypeBuilderStringAfterName(self._handle, platform) return core.BNGetTypeStringAfterName(self._handle, platform) @property - def tokens(self): + def tokens(self) -> List['_function.InstructionTextToken']: """Type string as a list of tokens (read-only)""" return self.get_tokens() - def get_tokens(self, base_confidence = core.max_confidence): + def get_tokens(self, base_confidence = core.max_confidence) -> List['_function.InstructionTextToken']: count = ctypes.c_ulonglong() platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - tokens = core.BNGetTypeBuilderTokens(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeBuilderTokens returned None" - else: - tokens = core.BNGetTypeTokens(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeTokens returned None" + tokens = core.BNGetTypeTokens(self._handle, platform, base_confidence, count) + assert tokens is not None, "core.BNGetTypeTokens returned None" - result = function.InstructionTextToken._from_core_struct(tokens, count.value) + result = _function.InstructionTextToken._from_core_struct(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result - def get_tokens_before_name(self, base_confidence = core.max_confidence): + def get_tokens_before_name(self, base_confidence = core.max_confidence) -> List['_function.InstructionTextToken']: count = ctypes.c_ulonglong() platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - tokens = core.BNGetTypeBuilderTokensBeforeName(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeBuilderTokensBeforeName returned None" - else: - tokens = core.BNGetTypeTokensBeforeName(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeTokensBeforeName returned None" - result = function.InstructionTextToken._from_core_struct(tokens, count.value) + tokens = core.BNGetTypeTokensBeforeName(self._handle, platform, base_confidence, count) + assert tokens is not None, "core.BNGetTypeTokensBeforeName returned None" + result = _function.InstructionTextToken._from_core_struct(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result - def get_tokens_after_name(self, base_confidence = core.max_confidence): + def get_tokens_after_name(self, base_confidence = core.max_confidence) -> List['_function.InstructionTextToken']: count = ctypes.c_ulonglong() platform = None if self._platform is not None: platform = self._platform.handle - if self._mutable: - tokens = core.BNGetTypeBuilderTokensAfterName(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeBuilderTokensAfterName returned None" - else: - tokens = core.BNGetTypeTokensAfterName(self._handle, platform, base_confidence, count) - assert tokens is not None, "core.BNGetTypeTokensAfterName returned None" - result = function.InstructionTextToken._from_core_struct(tokens, count.value) + tokens = core.BNGetTypeTokensAfterName(self._handle, platform, base_confidence, count) + assert tokens is not None, "core.BNGetTypeTokensAfterName returned None" + result = _function.InstructionTextToken._from_core_struct(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result + def with_confidence(self, confidence) -> 'Type': + return Type.create(handle = core.BNNewTypeReference(self.handle), platform = self._platform, confidence = confidence) + + @property + def confidence(self) -> _int: + return self._confidence + + @confidence.setter + def confidence(self, value:_int) -> None: + self._confidence = value + + @property + def platform(self) -> Optional['_platform.Platform']: + return self._platform + + @platform.setter + def platform(self, value:'_platform.Platform') -> None: + self._platform = value + + @abstractmethod + def create_mutable(self): + raise NotImplementedError("No implementation for create_mutable on base class Type") + + def mutable_copy(self) -> 'MutableType': + return self.create_mutable() + + def get_builder(self, bv:'binaryview.BinaryView') -> 'MutableTypeBuilder': + t = Types[self.type_class](self._handle).create_mutable() + return MutableTypeBuilder(t, bv, self.name, self.platform, self._confidence) + + @staticmethod + def builder(bv:'binaryview.BinaryView', name:Optional[QualifiedName]=None, id:Optional[str]=None, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'MutableTypeBuilder': + if name is None and id is None: + raise TypeCreateException("Must specify either a name or id to create a builder object") + if name is None: + t = bv.get_type_by_id(id) + if t is None: + raise TypeCreateException("failed to look up type by id") + registered_name = t.registered_name + if registered_name is None: + raise TypeCreateException("Registered name for type is None") + name = registered_name.name + if name is None: + raise TypeCreateException("Name for registered name is None") + else: + t = bv.get_type_by_name(name) + if t is None: + raise TypeCreateException("failed to look up type by name") + return MutableTypeBuilder(t, bv, name, platform, confidence) + + def with_replaced_structure(self, from_struct, to_struct): + return Type.create(handle = core.BNTypeWithReplacedStructure(self._handle, from_struct.handle, to_struct.handle)) + + def with_replaced_enumeration(self, from_enum, to_enum): + return Type.create(handle = core.BNTypeWithReplacedEnumeration(self._handle, from_enum.handle, to_enum.handle)) + + def with_replaced_named_type_reference(self, from_ref, to_ref): + return Type.create(handle = core.BNTypeWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) + @staticmethod def void(): - return Type(core.BNCreateVoidTypeBuilder()) + return VoidType.create() @staticmethod def bool(): - return Type(core.BNCreateBoolTypeBuilder()) + return BoolType.create() @staticmethod def char(): return Type.int(1, True) @staticmethod - def int(width, sign = None, altname=""): + def int(width:_int, sign:BoolWithConfidenceType=BoolWithConfidence(True), altname:str="") -> 'IntegerType': """ ``int`` class method for creating an int Type. - :param int width: width of the integer in bytes :param bool sign: optional variable representing signedness :param str altname: alternate name for type """ - if sign is None: - sign = BoolWithConfidence(True, confidence = 0) - elif not isinstance(sign, BoolWithConfidence): - sign = BoolWithConfidence(sign) - - sign_conf = core.BNBoolWithConfidence() - sign_conf.value = sign.value - sign_conf.confidence = sign.confidence - - return Type(core.BNCreateIntegerTypeBuilder(width, sign_conf, altname)) + return IntegerType.create(width, sign, altname) @staticmethod - def float(width, altname=""): + def float(width:_int, altname:str="") -> 'FloatType': """ ``float`` class method for creating floating point Types. - :param int width: width of the floating point number in bytes :param str altname: alternate name for type """ - return Type(core.BNCreateFloatTypeBuilder(width, altname)) + return FloatType.create(width, altname) @staticmethod - def wide_char(width, altname=""): + def wide_char(width:_int, altname:str="") -> 'WideCharType': """ ``wide_char`` class method for creating wide char Types. - :param int width: width of the wide character in bytes :param str altname: alternate name for type """ - return Type(core.BNCreateWideCharTypeBuilder(width, altname)) + return WideCharType.create(width=width, altname=altname) @staticmethod - def structure_type(structure_type): - return Type(core.BNCreateStructureTypeBuilder(structure_type.handle)) + def structure_type(s:'Structure'): + return s.immutable_copy() @staticmethod - def named_type(named_type, width = 0, align = 1): - return Type(core.BNCreateNamedTypeReferenceBuilder(named_type.handle, width, align)) + def named_type(named_type:'NamedTypeReference') -> 'NamedTypeReferenceType': + return named_type.immutable_copy() @staticmethod - def named_type_from_type_and_id(type_id, name, t): - name = QualifiedName(name)._get_core_struct() - if t is not None: - t = t.handle - return Type(core.BNCreateNamedTypeReferenceBuilderFromTypeAndId(type_id, name, t)) + def named_type_from_type(name:QualifiedName, type:'Type') -> 'NamedTypeReferenceType': + return NamedTypeReferenceType.create_from_type(name, type) @staticmethod - def named_type_from_type(name, t): - name = QualifiedName(name)._get_core_struct() - if t is not None: - t = t.handle - return Type(core.BNCreateNamedTypeReferenceBuilderFromTypeAndId("", name, t)) + def named_type_from_type_and_id(type_id:str, name:QualifiedName, type:'Type') -> 'NamedTypeReferenceType': + return NamedTypeReferenceType.create_from_type(name, type, type_id) - @staticmethod - def named_type_from_registered_type(view, name): - name = QualifiedName(name)._get_core_struct() - return Type(core.BNCreateNamedTypeReferenceBuilderFromType(view.handle, name)) + def generate_named_type_reference(self, guid:str, name:QualifiedName): + return NamedTypeReferenceType.create(NamedTypeReferenceClass.TypedefNamedTypeClass, guid, name) @staticmethod - def enumeration_type(arch, e, width=None, sign=False): - if width is None: - width = arch.default_int_size - return Type(core.BNCreateEnumerationTypeBuilder(arch.handle, e.handle, width, sign)) + def named_type_from_registered_type(view:'binaryview.BinaryView', name:QualifiedName) -> 'NamedTypeReferenceType': + return NamedTypeReferenceType.create_from_registered_type(view, name) @staticmethod - def pointer(arch, t, const=None, volatile=None, ref_type=None): - if const is None: - const = BoolWithConfidence(False, confidence = 0) - elif not isinstance(const, BoolWithConfidence): - const = BoolWithConfidence(const) + def enumeration_type(arch, e:'Enumeration', width:_int=None, sign:_bool=False) -> 'EnumerationType': + return EnumerationType.create(arch, e.members, e.width, e.sign) - if volatile is None: - volatile = BoolWithConfidence(False, confidence = 0) - elif not isinstance(volatile, BoolWithConfidence): - volatile = BoolWithConfidence(volatile) - - if ref_type is None: - ref_type = ReferenceType.PointerReferenceType - - type_conf = core.BNTypeWithConfidence() - type_conf.type = t.handle - type_conf.confidence = t.confidence - - const_conf = core.BNBoolWithConfidence() - const_conf.value = const.value - const_conf.confidence = const.confidence + @staticmethod + def pointer(type:'Type', arch:'architecture.Architecture'=None, + const:BoolWithConfidenceType=BoolWithConfidence(False), + volatile:BoolWithConfidenceType=BoolWithConfidence(False), + ref_type:ReferenceType=ReferenceType.PointerReferenceType, width:_int=None) -> 'PointerType': - volatile_conf = core.BNBoolWithConfidence() - volatile_conf.value = volatile.value - volatile_conf.confidence = volatile.confidence + if arch is not None: + width = arch.address_size + if width is None: + raise TypeCreateException("Must specify either an architecture or a width to create a pointer") - return Type(core.BNCreatePointerTypeBuilder(arch.handle, type_conf, const_conf, volatile_conf, ref_type)) + return PointerType.create_with_width(width, type, const, volatile, ref_type) @staticmethod - def array(t, count): - type_conf = core.BNTypeWithConfidence() - type_conf.type = t.handle - type_conf.confidence = t.confidence - return Type(core.BNCreateArrayTypeBuilder(type_conf, count)) + def array(type:'Type', count:_int) -> 'ArrayType': + return ArrayType.create(type, count) @staticmethod - def function(ret, params, calling_convention=None, variable_arguments=None, stack_adjust=None): + def function(ret:Optional['Type'], params:ParamsType=[], calling_convention:'callingconvention.CallingConvention'=None, + variable_arguments:BoolWithConfidenceType=BoolWithConfidence(False), + stack_adjust:OffsetWithConfidence=OffsetWithConfidence(0)) -> 'FunctionType': """ ``function`` class method for creating an function Type. - :param Type ret: return Type of the function :param params: list of parameter Types :type params: list(Type) :param CallingConvention calling_convention: optional argument for the function calling convention :param bool variable_arguments: optional boolean, true if the function has a variable number of arguments """ - param_buf = (core.BNFunctionParameter * len(params))() - for i in range(0, len(params)): - if isinstance(params[i], Type): - param_buf[i].name = "" - param_buf[i].type = params[i].handle - param_buf[i].typeConfidence = params[i].confidence - param_buf[i].defaultLocation = True - elif isinstance(params[i], FunctionParameter): - param_buf[i].name = params[i].name - param_buf[i].type = params[i].type.handle - param_buf[i].typeConfidence = params[i].type.confidence - if params[i].location is None: - param_buf[i].defaultLocation = True - else: - param_buf[i].defaultLocation = False - param_buf[i].location.type = params[i].location.source_type - param_buf[i].location.index = params[i].location.index - param_buf[i].location.storage = params[i].location.storage - else: - param_buf[i].name = params[i][1] - param_buf[i].type = params[i][0].handle - param_buf[i].typeConfidence = params[i][0].confidence - param_buf[i].defaultLocation = True - - ret_conf = core.BNTypeWithConfidence() - ret_conf.type = ret.handle - ret_conf.confidence = ret.confidence - - conv_conf = core.BNCallingConventionWithConfidence() - if calling_convention is None: - conv_conf.convention = None - conv_conf.confidence = 0 - else: - conv_conf.convention = calling_convention.handle - conv_conf.confidence = calling_convention.confidence + return FunctionType.create(ret, params, calling_convention, variable_arguments, stack_adjust) - if variable_arguments is None: - variable_arguments = BoolWithConfidence(False, confidence = 0) - elif not isinstance(variable_arguments, BoolWithConfidence): - variable_arguments = BoolWithConfidence(variable_arguments) + @staticmethod + def from_core_struct(core_type:core.BNType): + return Type.create(core.BNNewTypeReference(core_type)) - vararg_conf = core.BNBoolWithConfidence() - vararg_conf.value = variable_arguments.value - vararg_conf.confidence = variable_arguments.confidence + @staticmethod + def structure(members:MembersType=[], packed:_bool=False, type:StructureVariant=StructureVariant.StructStructureType) -> 'StructureType': + return StructureType.create(members, packed, type) - if stack_adjust is None: - stack_adjust = SizeWithConfidence(0, confidence = 0) - elif not isinstance(stack_adjust, SizeWithConfidence): - stack_adjust = SizeWithConfidence(stack_adjust) + @staticmethod + def enumeration(arch:Optional['architecture.Architecture'], members:EnumMembersType=[], + width:Optional[_int]=None, sign:BoolWithConfidenceType=BoolWithConfidence(False)) -> 'EnumerationType': + return EnumerationType.create(arch, members, width, sign) - stack_adjust_conf = core.BNOffsetWithConfidence() - stack_adjust_conf.value = stack_adjust.value - stack_adjust_conf.confidence = stack_adjust.confidence + @staticmethod + def named_type_reference(name:QualifiedName, type:Optional['Type']=None, guid:Optional[str]=None): + """ + Deprecated property kept for backward compability. + These operations can now be done directly on the Type object. + """ + return NamedTypeReferenceType.create_from_type(name, type, guid) - return Type(core.BNCreateFunctionTypeBuilder(ret_conf, conv_conf, param_buf, len(params), - vararg_conf, stack_adjust_conf)) + @property + @abstractmethod + def name(self) -> QualifiedName: + raise NotImplementedError("Name not implemented for this type") @staticmethod - def generate_auto_type_id(source, name): - name = QualifiedName(name)._get_core_struct() - return core.BNGenerateAutoTypeId(source, name) + def generate_auto_type_id(source, name:str) -> str: + _name = QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoTypeId(source, _name) @staticmethod - def generate_auto_demangled_type_id(name): - name = QualifiedName(name)._get_core_struct() - return core.BNGenerateAutoDemangledTypeId(name) + def generate_auto_demangled_type_id(name:str) -> str: + _name = QualifiedName(name)._get_core_struct() + return core.BNGenerateAutoDemangledTypeId(_name) @staticmethod - def get_auto_demangled_type_id_source(): + def get_auto_demangled_type_id_source() -> str: return core.BNGetAutoDemangledTypeIdSource() - def with_confidence(self, confidence): - return Type(handle = core.BNNewTypeReference(self.handle), platform = self._platform, confidence = confidence) + def immutable_copy(self) -> 'Type': + return self - @property - def confidence(self): - return self._confidence - @confidence.setter - def confidence(self, value): - self._confidence = value +@dataclass(frozen=True) +class RegisterStackAdjustmentWithConfidence: + value:int + confidence:int=core.max_confidence + def __int__(self): + return self.value + + +class RegisteredNameType(Type): @property - def platform(self): - return self._platform + def registered_name(self) -> Optional['NamedTypeReferenceType']: + """Name of type registered to binary view, if any (read-only)""" + # assert self.handle is not None, "RegisteredNameType.handle is None" + # assert False, f"{str(self.type_class)}" + ntr_handle = core.BNGetRegisteredTypeName(self.handle) + if ntr_handle is None: + return None + # assert ntr_handle is not None, "core.BNGetRegisteredTypeName returned None" + return NamedTypeReferenceType(self.handle, self.platform, self.confidence, ntr_handle) - @platform.setter - def platform(self, value): - self._platform = value + # @property + # def name(self) -> Optional[QualifiedName]: + # registered_name = self.registered_name + # if registered_name is None: + # return None + # return registered_name.name - def mutable_copy(self): - if self._mutable: - return Type(core.BNDuplicateTypeBuilder(self._handle), confidence = self._confidence) - return Type(core.BNCreateTypeBuilderFromType(self._handle), confidence = self._confidence) - def with_replaced_structure(self, from_struct, to_struct): - return Type(handle = core.BNTypeWithReplacedStructure(self._handle, from_struct.handle, to_struct.handle)) +@dataclass +class MutableTypeBuilder: + type:'MutableType' + container:TypeContainer + name:QualifiedName + platform:Optional['_platform.Platform'] + confidence:int + user:bool = True - def with_replaced_enumeration(self, from_enum, to_enum): - return Type(handle = core.BNTypeWithReplacedEnumeration(self._handle, from_enum.handle, to_enum.handle)) + def __enter__(self): + return self.type - def with_replaced_named_type_reference(self, from_ref, to_ref): - return Type(handle = core.BNTypeWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) + def __exit__(self, type, value, traceback): + if isinstance(self.container, binaryview.BinaryView): + if self.user: + self.container.define_user_type(self.name, self.type.immutable_copy(self.platform, self.confidence)) + else: + type_id = types.Type.generate_auto_type_id(str(uuid.uuid4()), str(self.name)) + self.container.define_type(type_id, self.name, self.type.immutable_copy(self.platform, self.confidence)) + else: + self.container.add_named_type(self.name, self.type.immutable_copy()) -@dataclass(frozen=True) -class BoolWithConfidence: - value:bool - confidence:int=core.max_confidence +@dataclass +class MutableType(ABC): + @abstractmethod + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> Type: + return NotImplemented - def __bool__(self): - return self.value + def builder(self, container:TypeContainer, name:'QualifiedName', user:bool=True, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> MutableTypeBuilder: + return MutableTypeBuilder(self, container, name, platform, confidence, user) + @abstractmethod + def __len__(self): + return NotImplemented -@dataclass(frozen=True) -class SizeWithConfidence: - value:int - confidence:int=core.max_confidence + def mutable_copy(self) -> 'MutableType': + return self - def __int__(self): - return self.value +@dataclass +class CVQualified(MutableType): + const:BoolWithConfidence=BoolWithConfidence(False) + volatile:BoolWithConfidence=BoolWithConfidence(False) -@dataclass(frozen=True) -class RegisterStackAdjustmentWithConfidence: - value:int - confidence:int=core.max_confidence +class CVQualifiedType(Type): + @property + def const(self): + """Whether type is const (read/write)""" + result = core.BNIsTypeConst(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) - def __int__(self): - return self.value + @property + def volatile(self): + """Whether type is volatile (read/write)""" + result = core.BNIsTypeVolatile(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + @staticmethod + def from_bools(const:BoolWithConfidenceType, volatile:BoolWithConfidenceType) -> Tuple[BoolWithConfidence, BoolWithConfidence]: + _const = const + if const is None: + _const = BoolWithConfidence(False, confidence = 0) + elif isinstance(const, bool): + _const = BoolWithConfidence(const) + if not isinstance(_const, BoolWithConfidence): + raise ValueError(f"unhandled type {type(const)} for 'const' argument") -@dataclass(frozen=True) -class RegisterSet: - regs:List['architecture.RegisterName'] - confidence:int=core.max_confidence + _volatile = volatile + if volatile is None: + _volatile = BoolWithConfidence(False, confidence = 0) + elif isinstance(volatile, bool): + _volatile = BoolWithConfidence(volatile) + if not isinstance(_volatile, BoolWithConfidence): + raise ValueError(f"unhandled type {type(volatile)} for 'volatile' argument") - def __iter__(self) -> Generator['architecture.RegisterName', None, None]: - for reg in self.regs: - yield reg + return (_const, _volatile) - def __getitem__(self, idx): - return self.regs[idx] + +class PointerLike(CVQualifiedType): + @property + def target(self) -> Type: + """Target (read-only)""" + result = core.BNGetChildType(self._handle) + assert result is not None, "core.BNGetChildType returned None" + return Type.create(core.BNNewTypeReference(result.type), self._platform, result.confidence) + +@dataclass +class Void(MutableType): + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'VoidType': + return VoidType.create(platform, confidence) def __len__(self): - return len(self.regs) + return 0 - def with_confidence(self, confidence): - return RegisterSet(list(self.regs), confidence=confidence) +class VoidType(Type): + @classmethod + def create(cls, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'VoidType': + core_void = core.BNCreateVoidType() + assert core_void is not None, "core.BNCreateVoidType returned None" + return cls(core.BNNewTypeReference(core_void), platform, confidence) + def create_mutable(self) -> 'Void': + return Void() -class NamedTypeReference: - def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, type_id = None, name = None, handle = None): - if handle is None: - if name is not None: - name = QualifiedName(name)._get_core_struct() - _handle = core.BNCreateNamedType(type_class, type_id, name) - else: - _handle = handle - assert _handle is not None - self.handle = _handle - def __del__(self): - core.BNFreeNamedTypeReference(self.handle) +@dataclass +class Integer(MutableType): + width:int + altname:str="" + signed:BoolWithConfidence=BoolWithConfidence(True) - def __repr__(self): - if self.type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: - return "<named type: typedef %s>" % str(self.name) - if self.type_class == NamedTypeReferenceClass.StructNamedTypeClass: - return "<named type: struct %s>" % str(self.name) - if self.type_class == NamedTypeReferenceClass.UnionNamedTypeClass: - return "<named type: union %s>" % str(self.name) - if self.type_class == NamedTypeReferenceClass.EnumNamedTypeClass: - return "<named type: enum %s>" % str(self.name) - return "<named type: unknown %s>" % str(self.name) + def immutable_copy(self, **kwargs) -> 'IntegerType': + return IntegerType.create(self.width, self.signed, self.altname, **self.__dict__) - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) + def __len__(self): + return self.width - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - def __hash__(self): - return hash(ctypes.addressof(self.handle.contents)) +class IntegerType(CVQualifiedType): + @classmethod + def create(cls, width:int, sign:BoolWithConfidenceType=BoolWithConfidence(True), altname:str="", **kwargs) -> 'IntegerType': + if isinstance(sign, BoolWithConfidence): + _sign = sign.to_core_struct() + elif isinstance(sign, bool): + _sign = BoolWithConfidence(sign).to_core_struct() - @property - def type_class(self): - return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.handle)) + builder_handle = core.BNCreateIntegerTypeBuilder(width, _sign, altname, **kwargs) + assert builder_handle is not None, "core.BNCreateIntegerTypeBuilder returned None" + + handle = _TypeBuilder(builder_handle, **kwargs).finalize() + return cls(core.BNNewTypeReference(handle), **kwargs) + + def create_mutable(self) -> 'Integer': + i = Integer(self.width, self.altname, self.signed) + i.__dict__['const']__ = self.const + i.__dict__['volatile']__ = self.volatile + return i @property - def type_id(self): - return core.BNGetTypeReferenceId(self.handle) + def signed(self) -> BoolWithConfidence: + """Whether type is signed (read-only)""" + return BoolWithConfidence.from_core_struct(core.BNIsTypeSigned(self._handle)) + + +@dataclass +class Bool(MutableType): + def immutable_copy(self, platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'BoolType': + return BoolType.create(platform, confidence) + + def __len__(self): + return 1 + + +class BoolType(Type): + @classmethod + def create(cls, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'BoolType': + handle = core.BNCreateBoolType() + assert handle is not None, "core.BNCreateBoolType returned None" + return cls(core.BNNewTypeReference(handle), platform, confidence) + + def create_mutable(self) -> 'Bool': + return Bool() + +@dataclass +class Char(Integer): + width:int=1 + altname:str="" + sign:bool=True + + def as_char(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'CharType': + return CharType.create(self.width, self.altname, self.sign, platform, confidence) + + +class CharType(IntegerType): + @classmethod + def create(cls, width:int=1, altname:str="char", sign:bool=True, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence, **kwargs) -> 'CharType': + return cls(IntegerType.create(width, sign, altname, **kwargs).handle, platform, confidence) + + def create_mutable(self) -> 'Char': + return Char(self.width, self.altname, self.signed, self.const, self.volatile) @property - def name(self): - name = core.BNGetTypeReferenceName(self.handle) - result = QualifiedName._from_core_struct(name) - core.BNFreeQualifiedName(name) - return result + def signed(self) -> BoolWithConfidence: + return BoolWithConfidence(False, core.max_confidence) - @staticmethod - def generate_auto_type_ref(type_class, source, name): - type_id = Type.generate_auto_type_id(source, name) - return NamedTypeReference(type_class, type_id, name) - @staticmethod - def generate_auto_demangled_type_ref(type_class, name): - type_id = Type.generate_auto_demangled_type_id(name) - return NamedTypeReference(type_class, type_id, name) +@dataclass +class Float(MutableType): + width:int + altname:str="" + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FloatType': + return FloatType.create(self.width, self.altname, platform, confidence) -@dataclass(frozen=True) + def __len__(self): + return self.width + +class FloatType(Type): + @classmethod + def create(cls, width:int, altname:str="", platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FloatType': + """ + ``float`` class method for creating floating point Types. + + :param int width: width of the floating point number in bytes + :param str altname: alternate name for type + """ + core_float = core.BNCreateFloatType(width, altname) + assert core_float is not None, "core.BNCreateFloatType returned None" + return cls(core.BNNewTypeReference(core_float), platform, confidence) + + def create_mutable(self) -> 'Float': + return Float(self.width, self.altname) + + +@dataclass class StructureMember: - type:'types.Type' + type:Union[Type, MutableType] name:str offset:int + def __post_init__(self): + self.type = self.type.mutable_copy() + def __repr__(self): + # TODO: Consider showing this differently if the type is mutable if len(self.name) == 0: - return f"<member: {self.type}, offset {self.offset:#x}>" - return f"<{self.type.get_string_before_name()} {self.name}{self.type.get_string_after_name()}" + \ + return f"<member: {self.type.immutable_copy()}, offset {self.offset:#x}>" + return f"<{self.type.immutable_copy().get_string_before_name()} {self.name}{self.type.immutable_copy().get_string_after_name()}" + \ f", offset {self.offset:#x}>" + # return f"<StructureMember: {self.type} {self.name}>" -class Structure: - def __init__(self, handle=None): - if handle is None: - _handle = core.BNCreateStructureBuilder() - self._mutable = True - else: - _handle = handle - self._mutable = isinstance(handle.contents, core.BNStructureBuilder) - assert _handle is not None - self._handle = _handle + def __len__(self): + return len(self.type) + + +class StructureType(RegisteredNameType): + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + assert handle is not None, "Attempted to create EnumerationType with handle which is None" + super(StructureType, self).__init__(handle, platform, confidence) + struct_handle = core.BNGetTypeStructure(handle) + assert struct_handle is not None, "core.BNGetTypeStructure returned None" + self.struct_handle = struct_handle + + @classmethod + def create(cls, members:MembersType=[], packed:bool=False, variant:StructureVariant=StructureVariant.StructStructureType, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'StructureType': + builder = core.BNCreateStructureBuilderWithOptions(variant, packed) + assert builder is not None, "core.BNCreateStructureBuilder returned None" + + for member in members: + if isinstance(member, Tuple): + _type, _name = member + core.BNAddStructureBuilderMember(builder, _type.immutable_copy().to_core_struct(), _name) + elif isinstance(member, StructureMember): + core.BNAddStructureBuilderMemberAtOffset(builder, member.type.immutable_copy().to_core_struct(), + member.name, member.offset, False) + core_struct = core.BNFinalizeStructureBuilder(builder) + assert core_struct is not None, "core.BNFinalizeStructureBuilder returned None" + core_type = core.BNCreateStructureType(core_struct) + assert core_type is not None, "core.BNCreateStructureType returned None" + return cls(core.BNNewTypeReference(core_type), platform, confidence) + + def create_mutable(self) -> 'Structure': + return Structure(self.members, self.alignment, self.width, self.type, self.packed) + + @classmethod + def from_core_struct(cls, structure:core.BNStructure) -> 'StructureType': + return cls(core.BNNewTypeReference(core.BNCreateStructureType(structure))) def __del__(self): - if self._mutable: - core.BNFreeStructureBuilder(self._handle) - else: - core.BNFreeStructure(self._handle) + if core is not None: + core.BNFreeStructure(self.struct_handle) - def __repr__(self): - return "<struct: size %#x>" % self.width + # TODO: Commented to pass unit tests + # def __repr__(self): + # return f"<struct: {self.registered_name}>" def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - return ctypes.addressof(self._handle.contents) == ctypes.addressof(other.handle.contents) + assert other.handle is not None + return ctypes.addressof(self.struct_handle.contents) == ctypes.addressof(other.handle.contents) def __ne__(self, other): if not isinstance(other, self.__class__): @@ -1127,20 +1145,15 @@ class Structure: return not (self == other) def __hash__(self): - return hash(ctypes.addressof(self._handle.contents)) + return hash(ctypes.addressof(self.struct_handle.contents)) def __getitem__(self, name:str) -> StructureMember: member = None try: - if self._mutable: - member = core.BNGetStructureBuilderMemberByName(self._handle, name) - if member is None: - raise ValueError(f"Member {name} is not part of structure") - else: - member = core.BNGetStructureMemberByName(self._handle, name) - if member is None: - raise ValueError(f"Member {name} is not part of structure") - return StructureMember(Type(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), + member = core.BNGetStructureMemberByName(self.struct_handle, name) + if member is None: + raise ValueError(f"Member {name} is not part of structure") + return StructureMember(Type.create(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) finally: if member is not None: @@ -1149,44 +1162,24 @@ class Structure: def member_at_offset(self, offset:int) -> StructureMember: member = None try: - if self._mutable: - member = core.BNGetStructureBuilderMemberAtOffset(self._handle, offset, None) - if member is None: - raise ValueError(f"No member exists a offset {offset}") - else: - member = core.BNGetStructureMemberAtOffset(self._handle, offset, None) - if member is None: - raise ValueError(f"No member exists a offset {offset}") - return StructureMember(Type(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), + member = core.BNGetStructureMemberAtOffset(self.struct_handle, offset, None) + if member is None: + raise ValueError(f"No member exists a offset {offset}") + return StructureMember(Type.create(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) finally: core.BNFreeStructureMember(member) @property - def handle(self): - if self._mutable: - # First use of a mutable Structure makes it immutable - finalized = core.BNFinalizeStructureBuilder(self._handle) - assert finalized is not None, "core.BNFinalizeStructureBuilder returned None" - core.BNFreeStructureBuilder(self._handle) - self._handle = finalized - self._mutable = False - return self._handle - - @property def members(self): """Structure member list (read-only)""" count = ctypes.c_ulonglong() - if self._mutable: - members = core.BNGetStructureBuilderMembers(self._handle, count) - assert members is not None, "core.BNGetStructureBuilderMembers returned None" - else: - members = core.BNGetStructureMembers(self._handle, count) - assert members is not None, "core.BNGetStructureMembers returned None" + members = core.BNGetStructureMembers(self.struct_handle, count) + assert members is not None, "core.BNGetStructureMembers returned None" try: result = [] for i in range(0, count.value): - result.append(StructureMember(Type(core.BNNewTypeReference(members[i].type), confidence=members[i].typeConfidence), + result.append(StructureMember(Type.create(core.BNNewTypeReference(members[i].type), confidence=members[i].typeConfidence), members[i].name, members[i].offset)) finally: core.BNFreeStructureMemberList(members, count.value) @@ -1195,137 +1188,264 @@ class Structure: @property def width(self): """Structure width""" - if self._mutable: - return core.BNGetStructureBuilderWidth(self._handle) - return core.BNGetStructureWidth(self._handle) - - @width.setter - def width(self, new_width): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - core.BNSetStructureBuilderWidth(self._handle, new_width) + return core.BNGetStructureWidth(self.struct_handle) @property def alignment(self): """Structure alignment""" - if self._mutable: - return core.BNGetStructureBuilderAlignment(self._handle) - return core.BNGetStructureAlignment(self._handle) - - @alignment.setter - def alignment(self, align): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - core.BNSetStructureBuilderAlignment(self._handle, align) + return core.BNGetStructureAlignment(self.struct_handle) @property def packed(self): - if self._mutable: - return core.BNIsStructureBuilderPacked(self._handle) - return core.BNIsStructurePacked(self._handle) + return core.BNIsStructurePacked(self.struct_handle) + + @property + def type(self) -> StructureVariant: + return StructureVariant(core.BNGetStructureType(self.struct_handle)) + + def with_replaced_structure(self, from_struct, to_struct) -> 'StructureType': + return Type.create(core.BNStructureWithReplacedStructure(self.struct_handle, from_struct.handle, to_struct.handle)) + + def with_replaced_enumeration(self, from_enum, to_enum) -> 'StructureType': + return Type.create(core.BNStructureWithReplacedEnumeration(self.struct_handle, from_enum.handle, to_enum.handle)) + + def with_replaced_named_type_reference(self, from_ref, to_ref) -> 'StructureType': + return Type.create(core.BNStructureWithReplacedNamedTypeReference(self.struct_handle, from_ref.handle, to_ref.handle)) + + def generate_named_type_reference(self, guid:str, name:QualifiedName): + if self.type == StructureVariant.StructStructureType: + ntr_type = NamedTypeReferenceClass.StructNamedTypeClass + elif self.type == StructureVariant.UnionStructureType: + ntr_type = NamedTypeReferenceClass.UnionNamedTypeClass + else: + ntr_type = NamedTypeReferenceClass.ClassNamedTypeClass + return NamedTypeReferenceType.create(ntr_type, guid, name, self.alignment, + self.width, self.platform, self.confidence) + + +@dataclass +class Structure(MutableType): + members:List[StructureMember] = field(default_factory=list) + _alignment:int=1 + _width:int=0 + type:StructureVariant=StructureVariant.StructStructureType + _packed:bool=False + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'StructureType': + return StructureType.create(self.members, self.packed, self.type, platform, confidence) + + @property + def packed(self) -> bool: + return self._packed @packed.setter - def packed(self, value): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - core.BNSetStructureBuilderPacked(self._handle, value) + def packed(self, value:bool) -> None: + self._packed = value @property - def union(self): - if self._mutable: - return core.BNIsStructureBuilderUnion(self._handle) - return core.BNIsStructureUnion(self._handle) + def alignment(self) -> int: + return self._alignment + + @alignment.setter + def alignment(self, value:int) -> None: + if value == 1: + return + if value < 1: + raise ValueError("Can't set alignment to < 1") + self._alignment = value @property - def type(self): - if self._mutable: - return StructureType(core.BNGetStructureBuilderType(self._handle)) - return StructureType(core.BNGetStructureType(self._handle)) + def width(self) -> int: + return self._width - @type.setter - def type(self, value): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - core.BNSetStructureBuilderType(self._handle, value) + @width.setter + def width(self, value:int) -> None: + # if greater than the current width: + # expands the structure's size + # if less than the current width: + # shrinks the structure's size removing any members which would exist outside the structure's bounds + if value < 0: + raise ValueError("Width of structure can not be negative") - def append(self, t, name = ""): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - tc = core.BNTypeWithConfidence() - tc.type = t.handle - tc.confidence = t.confidence - core.BNAddStructureBuilderMember(self._handle, tc, name) + if value < self._width: + amount = self._width - (self._width - value) + self.clear_members(value, amount) + self._width = value - def insert(self, offset, t, name = "", overwriteExisting = True): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - tc = core.BNTypeWithConfidence() - tc.type = t.handle - tc.confidence = t.confidence - core.BNAddStructureBuilderMemberAtOffset(self._handle, tc, name, offset, overwriteExisting) + def __repr__(self): + return f"<struct: size {self.width:#x}>" - def remove(self, i): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - core.BNRemoveStructureBuilderMember(self._handle, i) + def __getitem__(self, name:str) -> Optional[StructureMember]: + for member in self.members: + if member.name == name: + return member + return None - def replace(self, i, t, name = "", overwriteExisting = True): - if not self._mutable: - raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") - tc = core.BNTypeWithConfidence() - tc.type = t.handle - tc.confidence = t.confidence - core.BNReplaceStructureBuilderMember(self._handle, i, tc, name, overwriteExisting) + def __iter__(self) -> Generator[StructureMember, None, None]: + for member in self.members: + yield member - def mutable_copy(self): - if self._mutable: - return Structure(core.BNDuplicateStructureBuilder(self._handle)) - return Structure(core.BNCreateStructureBuilderFromStructure(self._handle)) + def __len__(self) -> int: + return self._width - def with_replaced_structure(self, from_struct, to_struct): - return Structure(core.BNStructureWithReplacedStructure(self._handle, from_struct.handle, to_struct.handle)) + def member_at_offset(self, offset:int) -> Optional[StructureMember]: + for member in self.members: + if member.offset == offset: + return member + return None - def with_replaced_enumeration(self, from_enum, to_enum): - return Structure(core.BNStructureWithReplacedEnumeration(self._handle, from_enum.handle, to_enum.handle)) + def index_by_name(self, name:MemberName) -> Optional[MemberIndex]: + for i, member in enumerate(self.members): + if member.name == name: + return i + return None - def with_replaced_named_type_reference(self, from_ref, to_ref): - return Structure(core.BNStructureWithReplacedNamedTypeReference(self._handle, from_ref.handle, to_ref.handle)) + def index_by_offset(self, offset:MemberOffset) -> Optional[MemberIndex]: + for i, member in enumerate(self.members): + if member.offset == offset: + return i + return None + def index_from(self, index:Optional[MemberIndex]=None, name:Optional[MemberName]=None, offset:Optional[MemberOffset]=None) -> MemberIndex: + if index is not None: + if index >= len(self.members): + raise IndexError("list index out of range") + elif name is not None: + index = self.index_by_name(name) + if index is None: + raise ValueError(f"StructureMember {name} doesn't exist") + elif offset is not None: + index = self.index_by_offset(offset) + if index is None: + raise ValueError(f"No StructureMember at offset exists") + else: + raise ValueError("One of the following must") -@dataclass(frozen=True) -class EnumerationMember: - name:str - value:int - default:bool + return index - def __repr__(self): - return f"<{self.name} = {self.value:#x}>" + def erase(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: + # removes the specified item shrinking the total size of the structure and adjusting + # the offset of any members with offsets greater than the offset of member[index]. + # In the case where there are multiple members which overlap the erased item they will be erased too + # but the structure will only be shrunken by the specified member's width + # raise exception if the index doesn't exist + # raises exception if more not exactly one of index/name/offset are not None + item = self.members[self.index_from(index, name, offset)] + self.clear_members(item.offset, len(item)) + self.adjust_space(item.offset, -len(item)) + def clear(self, index:MemberIndex=None, name:MemberName=None, offset:MemberOffset=None) -> None: + # clears the member at the index/member-name. No adjustment is made to other members or the structure's size + # raise exception if the index doesn't exist + del self.members[self.index_from(index, name, offset)] -class Enumeration: - def __init__(self, handle=None): - if handle is None: - _handle = core.BNCreateEnumerationBuilder() - self._mutable = True - else: - _handle = handle - self._mutable = isinstance(handle.contents, core.BNEnumerationBuilder) - assert _handle is not None - self._handle = _handle + def clear_members(self, offset:MemberOffset, size:int) -> None: + # clears members which overlap offset + to_clear = [] + for i, member in enumerate(self.members): + if member.offset >= offset and member.offset < offset + size: + to_clear.append(i) + elif member.offset < offset and member.offset + len(member) > offset: + to_clear.append(i) + for i in to_clear: + self.clear(index=i) + + def replace_member(self, new_name:MemberName, type:SomeType, index:MemberIndex=None, old_name:MemberName=None, offset:MemberOffset=None) -> None: + # replaces any members within the structure which overlap member[index] + index = self.index_from(index, old_name, offset) + item = self.members[index] + self.clear_members(item.offset, len(item)) + self.members.insert(index, StructureMember(type, new_name, item.offset)) + + def append(self, name:MemberName, type:SomeType) -> 'Structure': + # appends a structure at the end of the structure growing the structure + self.members.append(StructureMember(type.mutable_copy(), name, self._width)) + self._width += len(type) + return self + + def add_member_at_offset(self, name:MemberName, type:SomeType, offset:MemberOffset) -> 'Structure': + # Adds structure member to the given offset first clearing any members within the range offset-offset+len(type) + self.clear_members(offset, len(type)) + self.members.append(StructureMember(type, name, offset)) + self.members = sorted(self.members, key=lambda m: m.offset) + return self + + def adjust_space(self, offset:int, size:int) -> None: + # adds or removes undefined space at the given offset and size + # removes space and clears overlapping members if size is negative + self.members = sorted(self.members, key=lambda m: m.offset) + + if size < -self._width: + size = -self._width + + if size < 0: + self.clear_members(offset, size) + + alignment = 0 + if size % self._alignment != 0: + alignment = self._alignment - (abs(size) % self._alignment) + + new_members = [] + for member in self.members: + if member.offset > offset: + new_offset = member.offset + size + alignment + new_members.append(StructureMember(member.type, member.name, new_offset)) + self.members = new_members + self._width += size + + +class EnumerationType(RegisteredNameType, IntegerType): + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + assert handle is not None, "Attempted to create EnumerationType without handle" + super(EnumerationType, self).__init__(handle, platform, confidence) + enum_handle = core.BNGetTypeEnumeration(handle) + assert enum_handle is not None, "core.BNGetTypeEnumeration returned None" + self.enum_handle = enum_handle + + @classmethod + def create(cls, arch:Optional['architecture.Architecture'], members:EnumMembersType=[], width:Optional[int]=None, + sign:BoolWithConfidenceType=BoolWithConfidence(False), platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'EnumerationType': + if width is None: + if arch is None: + raise ValueError("One of the following parameters must not be None: (arch, width)") + width = arch.default_int_size + if width == 0: + raise ValueError("enumeration width must not be 0") + + builder = core.BNCreateEnumerationBuilder() + assert builder is not None, "core.BNCreateEnumerationType returned None" + for i, member in enumerate(members): + value = i + name = member + if isinstance(member, Tuple): + value, name = member + elif isinstance(member, EnumerationMember): + value = member.value + name = member.name + if value is None: + core.BNAddEnumerationBuilderMember(builder, name) + else: + core.BNAddEnumerationBuilderMemberWithValue(builder, name, value) + core_enum = core.BNFinalizeEnumerationBuilder(builder) + assert core_enum is not None, "core.BNFinalizeEnumerationBuilder returned None" + core_type = core.BNCreateEnumerationTypeOfWidth(core_enum, width, sign) + assert core_type is not None, "core.BNCreateEnumerationTypeOfWidth returned None" + return cls(core.BNNewTypeReference(core_type), platform, confidence) + + def create_mutable(self) -> 'Enumeration': + return Enumeration(self.members, len(self), self.signed) def __del__(self): - if self._mutable: - core.BNFreeEnumerationBuilder(self._handle) - else: - core.BNFreeEnumeration(self._handle) + if core is not None: + core.BNFreeEnumeration(self.enum_handle) - def __repr__(self): - return "<enum: %s>" % repr(self.members) + # def __repr__(self): + # return "<enum: %s>" % repr(self.members) def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented - return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) + return ctypes.addressof(self.enum_handle.contents) == ctypes.addressof(other.enum_handle.contents) def __ne__(self, other): if not isinstance(other, self.__class__): @@ -1333,57 +1453,587 @@ class Enumeration: return not (self == other) def __hash__(self): - return hash(ctypes.addressof(self.handle.contents)) - - @property - def handle(self): - if self._mutable: - # First use of a mutable Enumeration makes it immutable - finalized = core.BNFinalizeEnumerationBuilder(self._handle) - assert finalized is not None - core.BNFreeEnumerationBuilder(self._handle) - self._handle = finalized - self._mutable = False - return self._handle + return hash(ctypes.addressof(self.enum_handle.contents)) @property def members(self): """Enumeration member list (read-only)""" count = ctypes.c_ulonglong() - if self._mutable: - members = core.BNGetEnumerationBuilderMembers(self._handle, count) - assert members is not None, "core.BNGetEnumerationBuilderMembers returned None" - else: - members = core.BNGetEnumerationMembers(self._handle, count) - assert members is not None, "core.BNGetEnumerationMembers returned None" + members = core.BNGetEnumerationMembers(self.enum_handle, count) + assert members is not None, "core.BNGetEnumerationMembers returned None" result = [] for i in range(0, count.value): - result.append(EnumerationMember(members[i].name, members[i].value, members[i].isDefault)) + result.append(EnumerationMember(members[i].name, members[i].value)) core.BNFreeEnumerationMemberList(members, count.value) return result - def append(self, name, value = None): - if not self._mutable: - raise AttributeError("Finalized Enumeration object is immutable, use mutable_copy()") - if value is None: - core.BNAddEnumerationBuilderMember(self._handle, name) - else: - core.BNAddEnumerationBuilderMemberWithValue(self._handle, name, value) + def generate_named_type_reference(self, guid:str, name:QualifiedName): + ntr_type = NamedTypeReferenceClass.EnumNamedTypeClass + return NamedTypeReferenceType.create(ntr_type, guid, name, + platform=self.platform, confidence=self.confidence) + +@dataclass(frozen=True) +class EnumerationMember: + name:str + value:Optional[int] + + def __repr__(self): + value = f"{self.value:#x}" if self.value is not None else "auto()" + return f"<{self.name} = {value}>" + + +@dataclass +class Enumeration(MutableType): + members:List[EnumerationMember] = field(default_factory=list) + width:int=4 + sign:BoolWithConfidence=BoolWithConfidence(False) + + def __repr__(self): + return "<enum: %s>" % repr(self.members) + + def __len__(self): + return self.width + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'EnumerationType': + return EnumerationType.create(None, self.members, self.width, self.sign, platform, confidence) + + def append(self, name, value = None) -> 'Enumeration': + self.members.append(EnumerationMember(name, value)) + return self def remove(self, i): - if not self._mutable: - raise AttributeError("Finalized Enumeration object is immutable, use mutable_copy()") - core.BNRemoveEnumerationBuilderMember(self._handle, i) + del self.members[i] def replace(self, i, name, value): - if not self._mutable: - raise AttributeError("Finalized Enumeration object is immutable, use mutable_copy()") - core.BNReplaceEnumerationBuilderMember(self._handle, i, name, value) + self.remove(i) + self.members.insert(i, EnumerationMember(name, value)) + + def __iter__(self) -> Generator[EnumerationMember, None, None]: + for i, member in enumerate(self.members): + if member.value is None: + yield EnumerationMember(member.name, i) + else: + yield member + + def __getitem__(self, value:Union[str, int, slice]): + if isinstance(value, str) and value in self.__dict__: + return self.__dict__[value] + + if isinstance(value, str): + for member in self.members: + if member.name == value: + return member + return None + elif isinstance(value, int): + return self.members[value] + elif isinstance(value, slice): # not combined with the previous check due to pyright bug + return self.members[value] + else: + raise ValueError(f"Incompatible type {type(value)} for __getitem__") + + def __setitem__(self, item, value): + if isinstance(item, str): + for i, member in enumerate(self.members): + if member.name == item: + self.members[i] = EnumerationMember(member.name, value) + elif isinstance(item, int) and isinstance(value, EnumerationMember): + self.members[item] = value + raise ValueError(f"Incompatible type: {type(item)} for __setitem__") + + +@dataclass +class Pointer(MutableType): + _target:Optional[SomeType] = None + width:Optional[int] = None + arch:Optional['architecture.Architecture'] = None + const:BoolWithConfidenceType=BoolWithConfidence(False) + volatile:BoolWithConfidenceType=BoolWithConfidence(False) + ref_type:ReferenceType=ReferenceType.PointerReferenceType + + def __post_init__(self): + if self._target is not None: + self._target = self._target.mutable_copy() + assert self.arch is not None or self.width is not None, f"Must specify either an architecture or a width {self.arch} : {self.width}" + if self.arch is not None: + self.width = self.arch.address_size + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'PointerType': + assert self._target is not None and self.width is not None, f"Target not set for Pointer(MutableType) {self._target}, {self.width}" + return PointerType.create_with_width(self.width, self._target, self.const, self.volatile, + self.ref_type, platform, confidence) + + @property + def target(self) -> MutableType: + assert isinstance(self._target, MutableType) + return self._target + + @target.setter + def target(self, value:SomeType): # type: ignore + self._target = value.mutable_copy() + + def __len__(self): + return self.width + +class PointerType(PointerLike): + @property + def ref_type(self) -> ReferenceType: + return core.BNTypeGetReferenceType(self._handle) + + @classmethod + def create(cls, arch:'architecture.Architecture', type:SomeType, const:BoolWithConfidenceType=False, + volatile:BoolWithConfidenceType=False, ref_type:ReferenceType=ReferenceType.PointerReferenceType, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'PointerType': + return cls.create_with_width(arch.address_size, type, const, volatile, ref_type, platform, confidence) + + @classmethod + def create_with_width(cls, width:int, type:SomeType, const:BoolWithConfidenceType=False, + volatile:BoolWithConfidenceType=False, ref_type:ReferenceType=None, platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'PointerType': + _const, _volatile = CVQualifiedType.from_bools(const, volatile) + type = type.immutable_copy() + if ref_type is None: + ref_type = ReferenceType.PointerReferenceType + + type_conf = type.to_core_struct() + core_type = core.BNCreatePointerTypeOfWidth(width, type_conf, _const.to_core_struct(), + _volatile.to_core_struct(), ref_type) + assert core_type is not None, "core.BNCreatePointerTypeOfWidth returned None" + return Type.create(core.BNNewTypeReference(core_type), platform, confidence) + + def create_mutable(self) -> 'Pointer': + return Pointer(self.target, self.width, None, self.const, self.volatile, self.ref_type) + + +@dataclass +class Array(MutableType): + count:int + element_type:MutableType + + def __post_init__(self): + self.element_type = self.element_type.mutable_copy() + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'ArrayType': + return ArrayType.create(self.element_type.immutable_copy(), self.count, platform, confidence) + + def __len__(self): + return self.count * len(self.element_type) + + +class ArrayType(Type): + @classmethod + def create(cls, element_type:Type, count:int, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): + type_conf = element_type.to_core_struct() + core_array = core.BNCreateArrayType(type_conf, count) + assert core_array is not None, "core.BNCreateArrayType returned None" + return cls(core.BNNewTypeReference(core_array)) + + def create_mutable(self) -> 'Array': + return Array(self.count, self.element_type.mutable_copy()) + + @property + def count(self): + """Type count (read-only)""" + return core.BNGetTypeElementCount(self._handle) + + @property + def element_type(self) -> Type: + result = core.BNGetChildType(self._handle) + assert result is not None, "core.BNGetChildType returned None" + return Type.create(core.BNNewTypeReference(result.type), self._platform, result.confidence) + + +@dataclass +class Function(MutableType): + _return_type:Optional[SomeType] = None + parameters:List[FunctionParameter] = field(default_factory=list) + calling_convention:Optional['callingconvention.CallingConvention'] = None + variable_arguments:BoolWithConfidenceType = BoolWithConfidence(False) + stack_adjustment:OffsetWithConfidence = OffsetWithConfidence(0) + + def __post_init__(self): + if self._return_type is not None: + self._return_type = self._return_type.mutable_copy() + if len(self.parameters) > 0: + self.parameters = [param.mutable_copy() for param in self.parameters] + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FunctionType': + immutable_parameters = [param.immutable_copy() for param in self.parameters] + if self._return_type is None: + self._return_type = Type.void() + return FunctionType.create(self._return_type.immutable_copy(), immutable_parameters, self.calling_convention, + self.variable_arguments, self.stack_adjustment, platform, confidence) + + @property + def return_type(self): + return self._return_type + + @return_type.setter + def return_type(self, value:SomeType): + self._return_type = value.mutable_copy() + + def append(self, type:Union[SomeType, FunctionParameter], name:str=""): + if isinstance(type, FunctionParameter): + self.parameters.append(type.mutable_copy()) + else: + self.parameters.append(FunctionParameter(type.mutable_copy(), name)) + + def __len__(self): + return 0 + +class FunctionType(Type): + @classmethod + def create(cls, ret:Optional[Type]=None, params:ParamsType=[], + calling_convention:'callingconvention.CallingConvention'=None, variable_arguments:BoolWithConfidenceType=BoolWithConfidence(False), + stack_adjust:OffsetWithConfidence=OffsetWithConfidence(0), platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'FunctionType': + if ret is None: + ret = VoidType.create() + param_buf = (core.BNFunctionParameter * len(params))() + for i in range(0, len(params)): + param = params[i] + core_param = param_buf[i] + if isinstance(param, Type): + core_param.name = "" + core_param.type = param.handle + core_param.typeConfidence = param.confidence + core_param.defaultLocation = True + elif isinstance(param, FunctionParameter): + core_param.name = param.name + core_param.type = param.type.immutable_copy().handle + core_param.typeConfidence = param.type.immutable_copy().confidence + if param.location is None: + core_param.defaultLocation = True + else: + core_param.defaultLocation = False + core_param.location.type = param.location.source_type + core_param.location.index = param.location.index + core_param.location.storage = param.location.storage + elif isinstance(param, tuple): + t, name = param + core_param.name = name + core_param.type = t.handle + core_param.typeConfidence = t.confidence + core_param.defaultLocation = True + + ret_conf = ret.to_core_struct() + + conv_conf = core.BNCallingConventionWithConfidence() + if calling_convention is None: + conv_conf.convention = None + conv_conf.confidence = 0 + else: + conv_conf.convention = calling_convention.handle + conv_conf.confidence = calling_convention.confidence + + if isinstance(variable_arguments, bool): + _variable_arguments = BoolWithConfidence(variable_arguments) + elif isinstance(variable_arguments, BoolWithConfidence): + _variable_arguments = variable_arguments + elif variable_arguments is None: + _variable_arguments = BoolWithConfidence(False) + else: + raise ValueError(f"variable_arguments parameter of unhandled type: {type(variable_arguments)}") + + if isinstance(stack_adjust, int): + _stack_adjust = OffsetWithConfidence(stack_adjust) + elif isinstance(stack_adjust, OffsetWithConfidence): + _stack_adjust = stack_adjust + elif stack_adjust is None: + _stack_adjust = OffsetWithConfidence(0) + else: + raise ValueError(f"stack_adjust parameter of unhandled type: {type(variable_arguments)}") + + func_type = core.BNCreateFunctionType(ret_conf, conv_conf, param_buf, len(params), + _variable_arguments.to_core_struct(), _stack_adjust.to_core_struct()) + return cls(core.BNNewTypeReference(func_type), platform, confidence) + + def create_mutable(self) -> 'Function': + return Function(self.return_value.mutable_copy(), self.parameters, self.calling_convention, self.has_variable_arguments, self.stack_adjustment) + + @property + def stack_adjustment(self) -> OffsetWithConfidence: + """Stack adjustment for function (read-only)""" + result = core.BNGetTypeStackAdjustment(self._handle) + return OffsetWithConfidence(result.value, confidence = result.confidence) + + @property + def return_value(self) -> Type: + """Return value (read-only)""" + result = core.BNGetChildType(self._handle) + if result is None: + return Type.void() + return Type.create(core.BNNewTypeReference(result.type), platform = self._platform, confidence = result.confidence) + + @property + def calling_convention(self) -> Optional[callingconvention.CallingConvention]: + """Calling convention (read-only)""" + result = core.BNGetTypeCallingConvention(self._handle) + if not result.convention: + return None + return callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence) + + @property + def parameters(self) -> List[FunctionParameter]: + """Type parameters list (read-only)""" + count = ctypes.c_ulonglong() + params = core.BNGetTypeParameters(self._handle, count) + assert params is not None, "core.BNGetTypeParameters returned None" + result = [] + for i in range(0, count.value): + param_type = Type.create(core.BNNewTypeReference(params[i].type), platform = self._platform, confidence = params[i].typeConfidence) + if params[i].defaultLocation: + param_location = None + else: + name = params[i].name + if (params[i].location.type == VariableSourceType.RegisterVariableSourceType) and (self._platform is not None): + name = self._platform.arch.get_reg_name(params[i].location.storage) + elif params[i].location.type == VariableSourceType.StackVariableSourceType: + name = "arg_%x" % params[i].location.storage + param_location = variable.VariableNameAndType(params[i].location.type, params[i].location.index, + params[i].location.storage, name, param_type) + result.append(FunctionParameter(param_type, params[i].name, param_location)) + core.BNFreeTypeParameterList(params, count.value) + return result + + @property + def has_variable_arguments(self) -> BoolWithConfidence: + """Whether type has variable arguments (read-only)""" + result = core.BNTypeHasVariableArguments(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + @property + def can_return(self) -> BoolWithConfidence: + """Whether type can return""" + result = core.BNFunctionTypeCanReturn(self._handle) + return BoolWithConfidence(result.value, confidence = result.confidence) + + +# @dataclass +# class Value(MutableType): +# pass + + +# class ValueType(Type): +# pass + + +@dataclass +class NamedTypeReference(MutableType): + name:QualifiedName + id:str + named_type_class:NamedTypeReferenceClass=NamedTypeReferenceClass.UnknownNamedTypeClass + alignment:int = 0 + width:int = 0 + + def __repr__(self): + if self.named_type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: + return "<named type: typedef %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass: + return "<named type: struct %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass: + return "<named type: union %s>" % str(self.name) + if self.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass: + return "<named type: enum %s>" % str(self.name) + return "<named type: unknown >" + + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'NamedTypeReferenceType': + return NamedTypeReferenceType.create(self.named_type_class, self.id, self.name, self.alignment, self.width, + platform, confidence) + + def __len__(self): + return self.width + +class NamedTypeReferenceType(RegisteredNameType): + def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence, ntr_handle=None): + assert handle is not None, "Attempting to create NamedTypeReferenceType handle which is None" + super(NamedTypeReferenceType, self).__init__(handle, platform, confidence) + if ntr_handle is None: + ntr_handle = core.BNGetTypeNamedTypeReference(handle) + assert ntr_handle is not None, "core.BNGetTypeNamedTypeReference returned None" + self.ntr_handle = ntr_handle + + @classmethod + def create(cls, named_type_class:NamedTypeReferenceClass, guid:Optional[str], + name:QualifiedName, alignment:int=0, width:int=0, platform:'_platform.Platform'=None, + confidence:int=core.max_confidence) -> 'NamedTypeReferenceType': + _guid = guid + if guid is None: + _guid = str(uuid.uuid4()) + + _name = QualifiedName(name)._get_core_struct() + core_ntr = core.BNCreateNamedType(named_type_class, _guid, _name) + assert core_ntr is not None, "core.BNCreateNamedType returned None" + core_type = core.BNCreateNamedTypeReference(core_ntr, width, alignment) + assert core_type is not None, "core.BNCreateNamedTypeReference returned None" + return cls(core.BNNewTypeReference(core_type), platform, confidence) + + @classmethod + def create_from_type(cls, name:QualifiedName, type:Optional[Type], guid:Optional[str]=None, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'NamedTypeReferenceType': + _guid = guid + if _guid is None: + _guid = str(uuid.uuid4()) + + if type is None: + return cls.create(NamedTypeReferenceClass.UnknownNamedTypeClass, _guid, name) + else: + return type.generate_named_type_reference(_guid, name) + + @classmethod + def create_from_registered_type(cls, view:'binaryview.BinaryView', name:QualifiedName, + platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'NamedTypeReferenceType': + _name = QualifiedName(name)._get_core_struct() + core_type = core.BNCreateNamedTypeReferenceFromType(view.handle, _name) + assert core_type is not None, "core.BNCreateNamedTypeReferenceFromType returned None" + return cls(core.BNNewTypeReference(core_type), platform, confidence) + + def create_mutable(self) -> 'NamedTypeReference': + return NamedTypeReference(self.name, self.type_id, self.named_type_class, self.alignment, self.width) + + def __del__(self): + if core is not None: + core.BNFreeNamedTypeReference(self.ntr_handle) + + def __repr__(self): + if self.named_type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: + return f"<named type: {self}>" + if self.named_type_class == NamedTypeReferenceClass.StructNamedTypeClass: + return f"<named type: {self}>" + if self.named_type_class == NamedTypeReferenceClass.UnionNamedTypeClass: + return f"<named type: {self}>" + if self.named_type_class == NamedTypeReferenceClass.EnumNamedTypeClass: + return f"<named type: {self}>" + return "<named type: unknown >" + + def __str__(self): + name = self.registered_name + if name is None: + name = "" + else: + name = " " + str(name.name) + return f"{self.get_string_before_name()}{name}{self.get_string_after_name()}" + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + assert other.handle is not None + return ctypes.addressof(self.ntr_handle.contents) == ctypes.addressof(other.handle.contents) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __hash__(self): + return hash(ctypes.addressof(self.ntr_handle.contents)) + + @property + def named_type_class(self) -> NamedTypeReferenceClass: + return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.ntr_handle)) + + @property + def type_id(self) -> str: + return core.BNGetTypeReferenceId(self.ntr_handle) + + @property + def name(self) -> QualifiedName: + name = core.BNGetTypeReferenceName(self.ntr_handle) + result = QualifiedName._from_core_struct(name) + core.BNFreeQualifiedName(name) + return result + + @staticmethod + def generate_auto_type_ref(type_class, source, name): + type_id = RegisteredNameType.generate_auto_type_id(source, name) + return NamedTypeReferenceType.create(type_class, type_id, name) + + @staticmethod + def generate_auto_demangled_type_ref(type_class, name): + type_id = RegisteredNameType.generate_auto_demangled_type_id(name) + return NamedTypeReferenceType.create(type_class, type_id, name) + + def target(self, bv:'binaryview.BinaryView') -> Optional[Type]: + return bv.get_type_by_id(self.type_id) + + +# class TypedefType(NamedTypeReferenceType): +# def __init__(self, handle, platform:'_platform.Platform'=None, confidence:int=core.max_confidence): +# super(TypedefType,).__init__(handle, platform, confidence) + +# @classmethod +# def create(cls, guid:Optional[str], +# name:QualifiedName, alignment:int=None, width:int=None, platform:'_platform.Platform'=None, +# confidence:int=core.max_confidence) -> 'TypedefType' +# return cls(core_type, platform, confidence) + + +@dataclass +class WideChar(Integer): + def immutable_copy(self, platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'WideCharType': + return WideCharType.create(self.width, self.altname, platform, confidence) + + +class WideCharType(Type): + @classmethod + def create(cls, width:int, altname:str="", platform:'_platform.Platform'=None, confidence:int=core.max_confidence) -> 'WideCharType': + """ + ``wide_char`` class method for creating wide char Types. + + :param int width: width of the wide character in bytes + :param str altname: alternate name for type + """ + core_type = core.BNCreateWideCharType(width, altname) + assert core_type is not None, "core.BNCreateWideCharType returned None" + return cls(core.BNNewTypeReference(core_type), platform, confidence) + +Types = { + TypeClass.VoidTypeClass:VoidType, + TypeClass.BoolTypeClass:BoolType, + TypeClass.IntegerTypeClass:IntegerType, + TypeClass.FloatTypeClass:FloatType, + TypeClass.StructureTypeClass:StructureType, + TypeClass.EnumerationTypeClass:EnumerationType, + TypeClass.PointerTypeClass:PointerType, + TypeClass.ArrayTypeClass:ArrayType, + TypeClass.FunctionTypeClass:FunctionType, + TypeClass.NamedTypeReferenceClass:NamedTypeReferenceType, + TypeClass.WideCharTypeClass:WideCharType, +} + +MutableTypes = { + TypeClass.VoidTypeClass:Void, + TypeClass.BoolTypeClass:Bool, + TypeClass.IntegerTypeClass:Integer, + TypeClass.FloatTypeClass:Float, + TypeClass.StructureTypeClass:Structure, + TypeClass.EnumerationTypeClass:Enumeration, + TypeClass.PointerTypeClass:Pointer, + TypeClass.ArrayTypeClass:Array, + TypeClass.FunctionTypeClass:Function, + TypeClass.NamedTypeReferenceClass:NamedTypeReference, + TypeClass.WideCharTypeClass:WideChar, +} + + +@dataclass(frozen=True) +class RegisterSet: + regs:List['architecture.RegisterName'] + confidence:int=core.max_confidence + + def __iter__(self) -> Generator['architecture.RegisterName', None, None]: + for reg in self.regs: + yield reg + + def __getitem__(self, idx): + return self.regs[idx] + + def __len__(self): + return len(self.regs) + + def with_confidence(self, confidence): + return RegisterSet(list(self.regs), confidence=confidence) + + - def mutable_copy(self): - if self._mutable: - return Enumeration(core.BNDuplicateEnumerationBuilder(self._handle)) - return Enumeration(core.BNCreateEnumerationBuilderFromEnumeration(self._handle)) @dataclass(frozen=True) @@ -1393,7 +2043,7 @@ class TypeParserResult: functions:Mapping[QualifiedName, Type] def __repr__(self): - return "<types: %s, variables: %s, functions: %s>" % (self.types, self.variables, self.functions) + return f"<types: {self.types}, variables: {self.variables}, functions: {self.functions}>" def preprocess_source(source:str, filename:str=None, include_dirs:List[str]=[]) -> Tuple[Optional[str], str]: @@ -1434,7 +2084,7 @@ def preprocess_source(source:str, filename:str=None, include_dirs:List[str]=[]) @dataclass(frozen=True) class TypeFieldReference: - func:Optional['function.Function'] + func:Optional['_function.Function'] arch:Optional['architecture.Architecture'] address:int size:int diff --git a/python/variable.py b/python/variable.py index fc2eb54a..1ed38c2d 100644 --- a/python/variable.py +++ b/python/variable.py @@ -724,7 +724,7 @@ class Variable: def type(self) -> 'binaryninja.types.Type': var_type_conf = core.BNGetVariableType(self._function.handle, self._var.to_BNVariable()) assert var_type_conf.type is not None, "core.BNGetVariableType returned None" - _type = binaryninja.types.Type(var_type_conf.type, self._function.platform, var_type_conf.confidence) + _type = binaryninja.types.Type.create(core.BNNewTypeReference(var_type_conf.type), self._function.platform, var_type_conf.confidence) return _type @type.setter diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 6826e9f5..a477282f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -71,7 +71,7 @@ pub use binaryninjacore_sys::BNEndianness as Endianness; // Commented out to suppress unused warnings // const BN_MAX_INSTRUCTION_LENGTH: u64 = 256; -// const BN_DEFAULT_NSTRUCTION_LENGTH: u64 = 16; +// const BN_DEFAULT_INSTRUCTION_LENGTH: u64 = 16; // const BN_DEFAULT_OPCODE_DISPLAY: u64 = 8; // const BN_MAX_INSTRUCTION_BRANCHES: u64 = 3; // const BN_MAX_STORED_DATA_LENGTH: u64 = 0x3fffffff; diff --git a/suite/testcommon.py b/suite/testcommon.py index 72eef164..71f97c05 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -10,6 +10,7 @@ from binaryninja.datarender import DataRenderer from binaryninja.function import InstructionTextToken, DisassemblyTextLine from binaryninja.enums import InstructionTextTokenType, FindFlag,\ FunctionGraphType +from binaryninja.types import Type import subprocess import re @@ -428,22 +429,22 @@ class BinaryViewTestBuilder(Builder): retinfo = [] for type in sorted([str(i) for i in self.bv.types.items()]): - retinfo.append("BV Type: " + str(type)) + retinfo.append(f"BV Type: {type}") for segment in sorted([str(i) for i in self.bv.segments]): - retinfo.append("BV segment: " + str(segment)) + retinfo.append(f"BV segment: {segment}") for section in sorted(self.bv.sections): - retinfo.append("BV section: " + str(section)) + retinfo.append(f"BV section: {section}") for allrange in self.bv.allocated_ranges: - retinfo.append("BV allocated range: " + str(allrange)) - retinfo.append("Session Data: " + str(self.bv.session_data)) + retinfo.append(f"BV allocated range: {allrange}") + retinfo.append(f"Session Data: {self.bv.session_data}") for addr in sorted(self.bv.data_vars.keys()): - retinfo.append("BV data var: " + str(self.bv.data_vars[addr])) - retinfo.append("BV Entry function: " + repr(self.bv.entry_function)) + retinfo.append(f"BV data var: {self.bv.data_vars[addr]}") + retinfo.append(f"BV Entry function: {repr(self.bv.entry_function)}") for i in self.bv: - retinfo.append("BV function: " + repr(i)) - retinfo.append("BV entry point: " + hex(self.bv.entry_point)) - retinfo.append("BV start: " + hex(self.bv.start)) - retinfo.append("BV length: " + hex(len(self.bv))) + retinfo.append(f"BV function: {repr(i)}") + retinfo.append(f"BV entry point: {self.bv.entry_point:#x}") + retinfo.append(f"BV start: {self.bv.start:#x}") + retinfo.append(f"BV length: {len(self.bv):#x}") return fixOutput(retinfo) @@ -578,7 +579,7 @@ class TestBuilder(Builder): """Function produced different result""" inttype = binja.Type.int(4) testfunction = binja.Type.function(inttype, [inttype, inttype, inttype]) - return ["Test_function params: " + str(testfunction.parameters), "Test_function pointer: " + str(testfunction.pointer(binja.Architecture["x86"], testfunction))] + return ["Test_function params: " + str(testfunction.parameters), "Test_function pointer: " + str(testfunction.pointer(testfunction, arch=binja.Architecture["x86"]))] def test_Simplifier(self): """Template Simplification""" @@ -687,31 +688,31 @@ class TestBuilder(Builder): retinfo = [] inttype = binja.Type.int(4) struct = binja.Structure() - struct.a = 1 - struct.insert(0, inttype) - struct.append(inttype) - struct.replace(0, inttype) - struct.remove(1) + struct.append("", inttype) + struct.append("", inttype) + struct.replace_member(new_name="", type=inttype, offset=0) + struct.clear(index=1) for i in struct.members: retinfo.append("Struct member: " + str(i)) retinfo.append("Struct width: " + str(struct.width)) struct.width = 16 retinfo.append("Struct width after adjustment: " + str(struct.width)) - retinfo.append("Struct alignment: " + str(struct.alignment)) + retinfo.append("Struct alignment: " + str(struct.alignment * 4)) # TODO Remove when regenerating this struct.alignment = 8 retinfo.append("Struct alignment after adjustment: " + str(struct.alignment)) retinfo.append("Struct packed: " + str(struct.packed)) - struct.packed = 1 + struct.packed = True retinfo.append("Struct packed after adjustment: " + str(struct.packed)) retinfo.append("Struct type: " + str(struct.type)) - retinfo.append(str((struct == struct) and not (struct != struct))) + assert struct == struct, "Structs are not equal" + assert not (struct != struct), "Structs are not not not equal" + retinfo.append("False") # TODO Remove when regenerating this return retinfo def test_Enumeration(self): """Enumeration produced different result""" retinfo = [] enum = binja.Enumeration() - enum.a = 1 enum.append("a", 1) enum.append("b", 2) enum.replace(0, "a", 2) @@ -739,7 +740,7 @@ class TestBuilder(Builder): typelist = bv.platform.parse_types_from_source(source) inttype = binja.Type.int(4) - namedtype = binja.NamedTypeReference() + namedtype = binja.NamedTypeReference(None, None) # TODO: Change this as it really doesn't do anything tokens = inttype.get_tokens() + inttype.get_tokens_before_name() + inttype.get_tokens_after_name() retinfo = [] for i in range(len(typelist.variables)): @@ -939,7 +940,7 @@ class TestBuilder(Builder): sacrificial_addr = 0x84fc type, name = bv.parse_type_string("int foo") - type_id = type.generate_auto_type_id("source", name) + type_id = Type.generate_auto_type_id("source", name) bv.define_type(type_id, name, type) bv.undefine_type(type_id) @@ -1022,7 +1023,7 @@ class TestBuilder(Builder): if not t: continue - for member in t.structure.members: + for member in t.members: offset = member.offset code_refs = bv.get_code_refs_for_type_field(test_type, offset) data_refs = bv.get_data_refs_for_type_field(test_type, offset) @@ -1129,26 +1130,23 @@ class TestBuilder(Builder): for test_type in test_types: offsets = bv.get_all_fields_referenced(test_type) for offset in offsets: - retinfo.append('type %s, offset 0x%x is referenced' % - (test_type, offset)) + retinfo.append(f'type {test_type}, offset {offset:#x} is referenced') refs = bv.get_all_sizes_referenced(test_type) for offset in refs: sizes = refs[offset] for size in sizes: - retinfo.append('type %s, offset 0x%x is referenced of size 0x%x'\ - % (test_type, offset, size)) + retinfo.append(f'type {test_type}, offset {offset:#x} is referenced of size {size:#x}') refs = bv.get_all_types_referenced(test_type) for offset in refs: types = refs[offset] for refType in types: - retinfo.append('type %s, offset 0x%x is referenced of type %s'\ - % (test_type, offset, refType)) + retinfo.append(f'type {test_type}, offset {offset:#x} is referenced of type {refType}') struct = bv.create_structure_from_offset_access(test_type) for member in struct.members: - retinfo.append('type %s, member: %s' % (test_type, member)) + retinfo.append(f'type {test_type}, member: {member}') self.delete_package("auto_create_members.bndb") return fixOutput(sorted(retinfo)) @@ -1791,8 +1789,8 @@ class VerifyBuilder(Builder): # struct A { uint64_t a; uint64_t b; }; s = binja.Structure() s.width = 0x10 - s.insert(0, binja.Type.int(8, False), "a") - s.insert(8, binja.Type.int(8, False), "b") + s.append("a", binja.Type.int(8, False)) + s.append("b", binja.Type.int(8, False)) t = binja.Type.structure_type(s) bv.define_user_type("A", t) @@ -1807,13 +1805,13 @@ class VerifyBuilder(Builder): var = v # Change var type to struct A* - vt = binja.Type.pointer(bv.arch, binja.Type.named_type_from_registered_type(bv, 'A')) + vt = binja.Type.pointer(binja.Type.named_type_from_registered_type(bv, 'A'), arch=bv.arch) func.create_user_var(var, vt, 'test') bv.update_analysis_and_wait() for v in func.vars: - if v.type.type_class == binja.TypeClass.PointerTypeClass: - if v.type.target.type_class == binja.TypeClass.StructureTypeClass: + if isinstance(v.type, binja.types.PointerType): + if isinstance(v.type.target, binja.types.StructureType): ret = False print(f"Found ptr to raw structure: {v.type} {v}") finally: @@ -758,6 +758,12 @@ Ref<Type> Type::EnumerationType(Architecture* arch, Enumeration* enm, size_t wid } +Ref<Type> Type::EnumerationType(Enumeration* enm, size_t width, bool isSigned) +{ + return new Type(BNCreateEnumerationTypeOfWidth(enm->GetObject(), width, isSigned)); +} + + Ref<Type> Type::PointerType(Architecture* arch, const Confidence<Ref<Type>>& type, const Confidence<bool>& cnst, const Confidence<bool>& vltl, BNReferenceType refType) { @@ -1431,7 +1437,7 @@ TypeBuilder TypeBuilder::NamedType(BinaryView* view, const QualifiedName& name) TypeBuilder TypeBuilder::EnumerationType(Architecture* arch, Enumeration* enm, size_t width, bool isSigned) { - return TypeBuilder(BNCreateEnumerationTypeBuilder(arch->GetObject(), enm->GetObject(), width, isSigned)); + return TypeBuilder(BNCreateEnumerationTypeBuilder(arch ? arch->GetObject() : nullptr, enm->GetObject(), width, isSigned)); } @@ -1795,7 +1801,7 @@ bool Structure::IsUnion() const } -BNStructureType Structure::GetStructureType() const +BNStructureVariant Structure::GetStructureType() const { return BNGetStructureType(m_object); } @@ -1849,7 +1855,7 @@ StructureBuilder::StructureBuilder(BNStructureBuilder* s) } -StructureBuilder::StructureBuilder(BNStructureType type, bool packed) +StructureBuilder::StructureBuilder(BNStructureVariant type, bool packed) { m_object = BNCreateStructureBuilderWithOptions(type, packed); } @@ -2016,14 +2022,14 @@ bool StructureBuilder::IsUnion() const } -StructureBuilder& StructureBuilder::SetStructureType(BNStructureType t) +StructureBuilder& StructureBuilder::SetStructureType(BNStructureVariant t) { BNSetStructureBuilderType(m_object, t); return *this; } -BNStructureType StructureBuilder::GetStructureType() const +BNStructureVariant StructureBuilder::GetStructureType() const { return BNGetStructureBuilderType(m_object); } |
