summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2019-12-10 16:16:33 -0500
committerRusty Wagner <rusty@vector35.com>2019-12-17 12:35:07 -0500
commit142004d7f31ad2eee58dc6c9bdec7bdcc530cf58 (patch)
tree1afcba921cffdbe65cc66b90c72e934240e6b77a /python
parentdeb08e176008df25335557a95ceb73b24e2355ce (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.py2
-rw-r--r--python/types.py395
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):