diff options
| author | Rusty Wagner <rusty@vector35.com> | 2019-12-10 16:16:33 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2019-12-17 12:35:07 -0500 |
| commit | 142004d7f31ad2eee58dc6c9bdec7bdcc530cf58 (patch) | |
| tree | 1afcba921cffdbe65cc66b90c72e934240e6b77a /python | |
| parent | deb08e176008df25335557a95ceb73b24e2355ce (diff) | |
Immutable type/struct/enum objects, allowing deduplication for reduced memory usage.
In C++ API, modifying or creating types, structures, or enumerations
should be done with the new TypeBuilder, StructureBuilder, and
EnumerationBuilder objects, then converted to a final Type, Structure,
or Enumeration object using the Finalize method once the modifications
are complete. When modifying structures or enumerations inside existing
types, use the WithReplacedStructure or WithReplacedEnumeration methods
on the root type object and reregister the type to use the modified object.
In Python API, types, structures, and enumerations can be created as in
previous versions, but the objects become immutable once they are passed
to a method. To modify an existing type, structure, or enumeration, use the
mutable_copy() method. When modifying structures or enumerations, replace
the modified object in the Type with the with_replaced_structure() or
with_replaced_enumeration() methods.
Diffstat (limited to 'python')
| -rw-r--r-- | python/settings.py | 2 | ||||
| -rw-r--r-- | python/types.py | 395 |
2 files changed, 286 insertions, 111 deletions
diff --git a/python/settings.py b/python/settings.py index fec4023d..f81c8eef 100644 --- a/python/settings.py +++ b/python/settings.py @@ -65,7 +65,7 @@ class Settings(object): def __init__(self, instance_id = "default", handle = None): if handle is None: - if instance_id is None or instance_id is "": + if instance_id is None or instance_id == "": instance_id = "default" self._instance_id = instance_id if instance_id == "default": diff --git a/python/types.py b/python/types.py index ed4360d6..720f8568 100644 --- a/python/types.py +++ b/python/types.py @@ -320,12 +320,16 @@ class FunctionParameter(object): class Type(object): def __init__(self, handle, platform = None, confidence = max_confidence): - self.handle = handle + self._handle = handle + self._mutable = isinstance(handle.contents, core.BNTypeBuilder) self._confidence = confidence self._platform = platform def __del__(self): - core.BNFreeType(self.handle) + if self._mutable: + core.BNFreeTypeBuilder(self._handle) + else: + core.BNFreeType(self._handle) def __eq__(self, value): if not isinstance(value, Type): @@ -338,51 +342,101 @@ class Type(object): return core.BNTypesNotEqual(self.handle, value.handle) @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): """Type class (read-only)""" - return TypeClass(core.BNGetTypeClass(self.handle)) + if self._mutable: + return TypeClass(core.BNGetTypeBuilderClass(self._handle)) + return TypeClass(core.BNGetTypeClass(self._handle)) @property def width(self): """Type width (read-only)""" - return core.BNGetTypeWidth(self.handle) + if self._mutable: + return core.BNGetTypeBuilderWidth(self._handle) + return core.BNGetTypeWidth(self._handle) @property def alignment(self): """Type alignment (read-only)""" - return core.BNGetTypeAlignment(self.handle) + if self._mutable: + return core.BNGetTypeBuilderAlignment(self._handle) + return core.BNGetTypeAlignment(self._handle) @property def signed(self): """Wether type is signed (read-only)""" - result = core.BNIsTypeSigned(self.handle) + 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)""" - result = core.BNIsTypeConst(self.handle) + 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 = 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 = max_confidence - core.BNTypeSetConst(self.handle, bc) + core.BNTypeBuilderSetVolatile(self._handle, bc) @property - def modified(self): - """Whether type is modified (read-only)""" - return core.BNIsTypeFloatingPoint(self.handle) + 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)""" - result = core.BNGetChildType(self.handle) + 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) @@ -390,7 +444,10 @@ class Type(object): @property def element_type(self): """Target (read-only)""" - result = core.BNGetChildType(self.handle) + 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) @@ -398,7 +455,10 @@ class Type(object): @property def return_value(self): """Return value (read-only)""" - result = core.BNGetChildType(self.handle) + 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) @@ -406,7 +466,10 @@ class Type(object): @property def calling_convention(self): """Calling convention (read-only)""" - result = core.BNGetTypeCallingConvention(self.handle) + if self._mutable: + result = core.BNGetTypeBuilderCallingConvention(self._handle) + else: + result = core.BNGetTypeCallingConvention(self._handle) if not result.convention: return None return binaryninja.callingconvention.CallingConvention(None, handle = result.convention, confidence = result.confidence) @@ -415,7 +478,10 @@ class Type(object): def parameters(self): """Type parameters list (read-only)""" count = ctypes.c_ulonglong() - params = core.BNGetTypeParameters(self.handle, count) + if self._mutable: + params = core.BNGetTypeBuilderParameters(self._handle, count) + else: + params = core.BNGetTypeParameters(self._handle, count) result = [] for i in range(0, count.value): param_type = Type(core.BNNewTypeReference(params[i].type), platform = self._platform, confidence = params[i].typeConfidence) @@ -436,19 +502,28 @@ class Type(object): @property def has_variable_arguments(self): """Whether type has variable arguments (read-only)""" - result = core.BNTypeHasVariableArguments(self.handle) + 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 (read-only)""" - result = core.BNFunctionTypeCanReturn(self.handle) + if self._mutable: + result = core.BNFunctionTypeBuilderCanReturn(self._handle) + else: + result = core.BNFunctionTypeCanReturn(self._handle) return BoolWithConfidence(result.value, confidence = result.confidence) @property def structure(self): """Structure of the type (read-only)""" - result = core.BNGetTypeStructure(self.handle) + if self._mutable: + result = core.BNGetTypeBuilderStructure(self._handle) + else: + result = core.BNGetTypeStructure(self._handle) if result is None: return None return Structure(result) @@ -456,7 +531,10 @@ class Type(object): @property def enumeration(self): """Type enumeration (read-only)""" - result = core.BNGetTypeEnumeration(self.handle) + if self._mutable: + result = core.BNGetTypeBuilderEnumeration(self._handle) + else: + result = core.BNGetTypeEnumeration(self._handle) if result is None: return None return Enumeration(result) @@ -464,7 +542,10 @@ class Type(object): @property def named_type_reference(self): """Reference to a named type (read-only)""" - result = core.BNGetTypeNamedTypeReference(self.handle) + if self._mutable: + result = core.BNGetTypeBuilderNamedTypeReference(self._handle) + else: + result = core.BNGetTypeNamedTypeReference(self._handle) if result is None: return None return NamedTypeReference(handle = result) @@ -472,17 +553,24 @@ class Type(object): @property def count(self): """Type count (read-only)""" - return core.BNGetTypeElementCount(self.handle) + if self._mutable: + return core.BNGetTypeBuilderElementCount(self._handle) + return core.BNGetTypeElementCount(self._handle) @property def offset(self): """Offset into structure (read-only)""" - return core.BNGetTypeOffset(self.handle) + if self._mutable: + return core.BNGetTypeBuilderOffset(self._handle) + return core.BNGetTypeOffset(self._handle) @property def stack_adjustment(self): """Stack adjustment for function (read-only)""" - result = core.BNGetTypeStackAdjustment(self.handle) + if self._mutable: + result = core.BNGetTypeBuilderStackAdjustment(self._handle) + else: + result = core.BNGetTypeStackAdjustment(self._handle) return SizeWithConfidence(result.value, confidence = result.confidence) def __len__(self): @@ -492,7 +580,9 @@ class Type(object): platform = None if self._platform is not None: platform = self._platform.handle - return core.BNGetTypeString(self.handle, platform) + if self._mutable: + return core.BNGetTypeBuilderString(self._handle, platform) + return core.BNGetTypeString(self._handle, platform) def __repr__(self): if self._confidence < max_confidence: @@ -503,13 +593,17 @@ class Type(object): platform = None if self._platform is not None: platform = self._platform.handle - return core.BNGetTypeStringBeforeName(self.handle, platform) + if self._mutable: + return core.BNGetTypeBuilderStringBeforeName(self._handle, platform) + return core.BNGetTypeStringBeforeName(self._handle, platform) def get_string_after_name(self): platform = None if self._platform is not None: platform = self._platform.handle - return core.BNGetTypeStringAfterName(self.handle, platform) + if self._mutable: + return core.BNGetTypeBuilderStringAfterName(self._handle, platform) + return core.BNGetTypeStringAfterName(self._handle, platform) @property def tokens(self): @@ -521,7 +615,10 @@ class Type(object): platform = None if self._platform is not None: platform = self._platform.handle - tokens = core.BNGetTypeTokens(self.handle, platform, base_confidence, count) + if self._mutable: + tokens = core.BNGetTypeBuilderTokens(self._handle, platform, base_confidence, count) + else: + tokens = core.BNGetTypeTokens(self._handle, platform, base_confidence, count) result = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result @@ -531,7 +628,10 @@ class Type(object): platform = None if self._platform is not None: platform = self._platform.handle - tokens = core.BNGetTypeTokensBeforeName(self.handle, platform, base_confidence, count) + if self._mutable: + tokens = core.BNGetTypeBuilderTokensBeforeName(self._handle, platform, base_confidence, count) + else: + tokens = core.BNGetTypeTokensBeforeName(self._handle, platform, base_confidence, count) result = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result @@ -541,18 +641,21 @@ class Type(object): platform = None if self._platform is not None: platform = self._platform.handle - tokens = core.BNGetTypeTokensAfterName(self.handle, platform, base_confidence, count) + if self._mutable: + tokens = core.BNGetTypeBuilderTokensAfterName(self._handle, platform, base_confidence, count) + else: + tokens = core.BNGetTypeTokensAfterName(self._handle, platform, base_confidence, count) result = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens, count.value) core.BNFreeInstructionText(tokens, count.value) return result @classmethod def void(cls): - return Type(core.BNCreateVoidType()) + return Type(core.BNCreateVoidTypeBuilder()) @classmethod def bool(self): - return Type(core.BNCreateBoolType()) + return Type(core.BNCreateBoolTypeBuilder()) @classmethod def char(self): @@ -576,7 +679,7 @@ class Type(object): sign_conf.value = sign.value sign_conf.confidence = sign.confidence - return Type(core.BNCreateIntegerType(width, sign_conf, altname)) + return Type(core.BNCreateIntegerTypeBuilder(width, sign_conf, altname)) @classmethod def float(self, width, altname=""): @@ -586,40 +689,40 @@ class Type(object): :param int width: width of the floating point number in bytes :param str altname: alternate name for type """ - return Type(core.BNCreateFloatType(width, altname)) + return Type(core.BNCreateFloatTypeBuilder(width, altname)) @classmethod def structure_type(self, structure_type): - return Type(core.BNCreateStructureType(structure_type.handle)) + return Type(core.BNCreateStructureTypeBuilder(structure_type.handle)) @classmethod def named_type(self, named_type, width = 0, align = 1): - return Type(core.BNCreateNamedTypeReference(named_type.handle, width, align)) + return Type(core.BNCreateNamedTypeReferenceBuilder(named_type.handle, width, align)) @classmethod def named_type_from_type_and_id(self, type_id, name, t): name = QualifiedName(name)._get_core_struct() if t is not None: t = t.handle - return Type(core.BNCreateNamedTypeReferenceFromTypeAndId(type_id, name, t)) + return Type(core.BNCreateNamedTypeReferenceBuilderFromTypeAndId(type_id, name, t)) @classmethod def named_type_from_type(self, name, t): name = QualifiedName(name)._get_core_struct() if t is not None: t = t.handle - return Type(core.BNCreateNamedTypeReferenceFromTypeAndId("", name, t)) + return Type(core.BNCreateNamedTypeReferenceBuilderFromTypeAndId("", name, t)) @classmethod def named_type_from_registered_type(self, view, name): name = QualifiedName(name)._get_core_struct() - return Type(core.BNCreateNamedTypeReferenceFromType(view.handle, name)) + return Type(core.BNCreateNamedTypeReferenceBuilderFromType(view.handle, name)) @classmethod def enumeration_type(self, arch, e, width=None, sign=False): if width is None: width = arch.default_int_size - return Type(core.BNCreateEnumerationType(arch.handle, e.handle, width, sign)) + return Type(core.BNCreateEnumerationTypeBuilder(arch.handle, e.handle, width, sign)) @classmethod def pointer(self, arch, t, const=None, volatile=None, ref_type=None): @@ -648,14 +751,14 @@ class Type(object): volatile_conf.value = volatile.value volatile_conf.confidence = volatile.confidence - return Type(core.BNCreatePointerType(arch.handle, type_conf, const_conf, volatile_conf, ref_type)) + return Type(core.BNCreatePointerTypeBuilder(arch.handle, type_conf, const_conf, volatile_conf, ref_type)) @classmethod def array(self, t, count): type_conf = core.BNTypeWithConfidence() type_conf.type = t.handle type_conf.confidence = t.confidence - return Type(core.BNCreateArrayType(type_conf, count)) + return Type(core.BNCreateArrayTypeBuilder(type_conf, count)) @classmethod def function(self, ret, params, calling_convention=None, variable_arguments=None, stack_adjust=None): @@ -722,7 +825,7 @@ class Type(object): stack_adjust_conf.value = stack_adjust.value stack_adjust_conf.confidence = stack_adjust.confidence - return Type(core.BNCreateFunctionType(ret_conf, conv_conf, param_buf, len(params), + return Type(core.BNCreateFunctionTypeBuilder(ret_conf, conv_conf, param_buf, len(params), vararg_conf, stack_adjust_conf)) @classmethod @@ -742,12 +845,6 @@ class Type(object): def with_confidence(self, confidence): return Type(handle = core.BNNewTypeReference(self.handle), platform = self._platform, confidence = confidence) - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - @property def confidence(self): """ """ @@ -766,6 +863,20 @@ class Type(object): def platform(self, value): self._platform = value + 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)) + + def with_replaced_enumeration(self, from_enum, to_enum): + return Type(handle = core.BNTypeWithReplacedEnumeration(self.handle, from_enum.handle, to_enum.handle)) + + def with_replaced_named_type_reference(self, from_ref, to_ref): + return Type(handle = core.BNTypeWithReplacedNamedTypeReference(self.handle, from_ref.handle, to_ref.handle)) + class BoolWithConfidence(object): def __init__(self, value, confidence = max_confidence): @@ -942,13 +1053,9 @@ class ReferenceTypeWithConfidence(object): class NamedTypeReference(object): def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, type_id = None, name = None, handle = None): if handle is None: - self.handle = core.BNCreateNamedType() - core.BNSetTypeReferenceClass(self.handle, type_class) - if type_id is not None: - core.BNSetTypeReferenceId(self.handle, type_id) if name is not None: name = QualifiedName(name)._get_core_struct() - core.BNSetTypeReferenceName(self.handle, name) + self.handle = core.BNCreateNamedType(type_class, type_id, name) else: self.handle = handle @@ -969,18 +1076,10 @@ class NamedTypeReference(object): def type_class(self): return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.handle)) - @type_class.setter - def type_class(self, value): - core.BNSetTypeReferenceClass(self.handle, value) - @property def type_id(self): return core.BNGetTypeReferenceId(self.handle) - @type_id.setter - def type_id(self, value): - core.BNSetTypeReferenceId(self.handle, value) - @property def name(self): name = core.BNGetTypeReferenceName(self.handle) @@ -988,11 +1087,6 @@ class NamedTypeReference(object): core.BNFreeQualifiedName(name) return result - @name.setter - def name(self, value): - value = QualifiedName(value)._get_core_struct() - core.BNSetTypeReferenceName(self.handle, value) - def __repr__(self): if self.type_class == NamedTypeReferenceClass.TypedefNamedTypeClass: return "<named type: typedef %s>" % str(self.name) @@ -1058,26 +1152,34 @@ class StructureMember(object): class Structure(object): def __init__(self, handle=None): if handle is None: - self.handle = core.BNCreateStructure() + self._handle = core.BNCreateStructureBuilder() + self._mutable = True else: - self.handle = handle + self._handle = handle + self._mutable = isinstance(handle.contents, core.BNStructureBuilder) def __del__(self): - core.BNFreeStructure(self.handle) + if self._mutable: + core.BNFreeStructureBuilder(self._handle) + else: + core.BNFreeStructure(self._handle) def __eq__(self, value): if not isinstance(value, Structure): return False - return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + return ctypes.addressof(self._handle.contents) == ctypes.addressof(value._handle.contents) def __ne__(self, value): if not isinstance(value, Structure): return True - return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + return ctypes.addressof(self._handle.contents) != ctypes.addressof(value._handle.contents) def __getitem__(self, name): try: - member = core.BNGetStructureMemberByName(self.handle, name) + if self._mutable: + member = core.BNGetStructureBuilderMemberByName(self._handle, name) + else: + member = core.BNGetStructureMemberByName(self._handle, name) return StructureMember(Type(core.BNNewTypeReference(member.contents.type), confidence=member.contents.typeConfidence), member.contents.name, member.contents.offset) finally: @@ -1085,17 +1187,33 @@ class Structure(object): def member_at_offset(self, offset): try: - member = core.BNGetStructureMemberAtOffset(self.handle, offset) + if self._mutable: + member = core.BNGetStructureBuilderMemberAtOffset(self._handle, offset, None) + else: + member = core.BNGetStructureMemberAtOffset(self._handle, offset, None) return StructureMember(Type(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) + 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() - members = core.BNGetStructureMembers(self.handle, count) + if self._mutable: + members = core.BNGetStructureBuilderMembers(self._handle, count) + else: + members = core.BNGetStructureMembers(self._handle, count) try: result = [] for i in range(0, count.value): @@ -1108,70 +1226,104 @@ class Structure(object): @property def width(self): """Structure width""" - return core.BNGetStructureWidth(self.handle) + if self._mutable: + return core.BNGetStructureBuilderWidth(self._handle) + return core.BNGetStructureWidth(self._handle) @width.setter def width(self, new_width): - core.BNSetStructureWidth(self.handle, new_width) + if not self._mutable: + raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") + core.BNSetStructureBuilderWidth(self._handle, new_width) @property def alignment(self): """Structure alignment""" - return core.BNGetStructureAlignment(self.handle) + if self._mutable: + return core.BNGetStructureBuilderAlignment(self._handle) + return core.BNGetStructureAlignment(self._handle) @alignment.setter def alignment(self, align): - core.BNSetStructureAlignment(self.handle, align) + if not self._mutable: + raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") + core.BNSetStructureBuilderAlignment(self._handle, align) @property def packed(self): - return core.BNIsStructurePacked(self.handle) + if self._mutable: + return core.BNIsStructureBuilderPacked(self._handle) + return core.BNIsStructurePacked(self._handle) @packed.setter def packed(self, value): - core.BNSetStructurePacked(self.handle, value) + if not self._mutable: + raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") + core.BNSetStructureBuilderPacked(self._handle, value) @property def union(self): - return core.BNIsStructureUnion(self.handle) + if self._mutable: + return core.BNIsStructureBuilderUnion(self._handle) + return core.BNIsStructureUnion(self._handle) @property def type(self): - return StructureType(core.BNGetStructureType(self.handle)) + if self._mutable: + return StructureType(core.BNGetStructureBuilderType(self._handle)) + return StructureType(core.BNGetStructureType(self._handle)) @type.setter def type(self, value): - core.BNSetStructureType(self.handle, value) - - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) + if not self._mutable: + raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") + core.BNSetStructureBuilderType(self._handle, value) def __repr__(self): return "<struct: size %#x>" % self.width 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.BNAddStructureMember(self.handle, tc, name) + core.BNAddStructureBuilderMember(self._handle, tc, name) def insert(self, offset, 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.BNAddStructureMemberAtOffset(self.handle, tc, name, offset) + core.BNAddStructureBuilderMemberAtOffset(self._handle, tc, name, offset) def remove(self, i): - core.BNRemoveStructureMember(self.handle, i) + if not self._mutable: + raise AttributeError("Finalized Structure object is immutable, use mutable_copy()") + core.BNRemoveStructureBuilderMember(self._handle, i) def replace(self, i, 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.BNReplaceStructureMember(self.handle, i, tc, name) + core.BNReplaceStructureBuilderMember(self._handle, i, tc, name) + + def mutable_copy(self): + if self._mutable: + return Structure(core.BNDuplicateStructureBuilder(self._handle)) + return Structure(core.BNCreateStructureBuilderFromStructure(self._handle)) + + def with_replaced_structure(self, from_struct, to_struct): + return Structure(core.BNStructureWithReplacedStructure(self.handle, from_struct.handle, to_struct.handle)) + + def with_replaced_enumeration(self, from_enum, to_enum): + return Structure(core.BNStructureWithReplacedEnumeration(self.handle, from_enum.handle, to_enum.handle)) + + def with_replaced_named_type_reference(self, from_ref, to_ref): + return Structure(core.BNStructureWithReplacedNamedTypeReference(self.handle, from_ref.handle, to_ref.handle)) class EnumerationMember(object): @@ -1214,54 +1366,77 @@ class EnumerationMember(object): class Enumeration(object): def __init__(self, handle=None): if handle is None: - self.handle = core.BNCreateEnumeration() + self._handle = core.BNCreateEnumerationBuilder() + self._mutable = True else: - self.handle = handle + self._handle = handle + self._mutable = isinstance(handle.contents, core.BNEnumerationBuilder) def __del__(self): - core.BNFreeEnumeration(self.handle) + if self._mutable: + core.BNFreeEnumerationBuilder(self._handle) + else: + core.BNFreeEnumeration(self._handle) def __eq__(self, value): if not isinstance(value, Enumeration): return False - return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents) + return ctypes.addressof(self._handle.contents) == ctypes.addressof(value._handle.contents) def __ne__(self, value): if not isinstance(value, Enumeration): return True - return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents) + return ctypes.addressof(self._handle.contents) != ctypes.addressof(value._handle.contents) + + @property + def handle(self): + if self._mutable: + # First use of a mutable Enumeration makes it immutable + finalized = core.BNFinalizeEnumerationBuilder(self._handle) + core.BNFreeEnumerationBuilder(self._handle) + self._handle = finalized + self._mutable = False + return self._handle @property def members(self): """Enumeration member list (read-only)""" count = ctypes.c_ulonglong() - members = core.BNGetEnumerationMembers(self.handle, count) + if self._mutable: + members = core.BNGetEnumerationBuilderMembers(self._handle, count) + else: + members = core.BNGetEnumerationMembers(self._handle, count) result = [] for i in range(0, count.value): result.append(EnumerationMember(members[i].name, members[i].value, members[i].isDefault)) core.BNFreeEnumerationMemberList(members, count.value) return result - def __setattr__(self, name, value): - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) - def __repr__(self): return "<enum: %s>" % repr(self.members) 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.BNAddEnumerationMember(self.handle, name) + core.BNAddEnumerationBuilderMember(self._handle, name) else: - core.BNAddEnumerationMemberWithValue(self.handle, name, value) + core.BNAddEnumerationBuilderMemberWithValue(self._handle, name, value) def remove(self, i): - core.BNRemoveEnumerationMember(self.handle, i) + if not self._mutable: + raise AttributeError("Finalized Enumeration object is immutable, use mutable_copy()") + core.BNRemoveEnumerationBuilderMember(self._handle, i) def replace(self, i, name, value): - core.BNReplaceEnumerationMember(self.handle, i, name, value) + if not self._mutable: + raise AttributeError("Finalized Enumeration object is immutable, use mutable_copy()") + core.BNReplaceEnumerationBuilderMember(self._handle, i, name, value) + + def mutable_copy(self): + if self._mutable: + return Enumeration(core.BNDuplicateEnumerationBuilder(self._handle)) + return Enumeration(core.BNCreateEnumerationBuilderFromEnumeration(self._handle)) class TypeParserResult(object): |
