summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h30
-rw-r--r--binaryninjacore.h30
-rw-r--r--datarenderer.cpp184
-rw-r--r--python/__init__.py1
-rw-r--r--python/datarender.py181
-rw-r--r--python/downloadprovider.py3
-rw-r--r--python/types.py14
-rw-r--r--type.cpp20
8 files changed, 460 insertions, 3 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 2b3273a8..958697c7 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -2185,6 +2185,9 @@ namespace BinaryNinja
public:
Type(BNType* type);
+ bool operator==(const Type& other);
+ bool operator!=(const Type& other);
+
BNTypeClass GetClass() const;
uint64_t GetWidth() const;
size_t GetAlignment() const;
@@ -2209,6 +2212,7 @@ namespace BinaryNinja
void SetVolatile(const Confidence<bool>& vltl);
void SetTypeName(const QualifiedName& name);
Confidence<int64_t> GetStackAdjustment() const;
+ QualifiedName GetStructureName() const;
uint64_t GetElementCount() const;
uint64_t GetOffset() const;
@@ -4324,4 +4328,30 @@ namespace BinaryNinja
bool IsArray() const;
bool IsKeyValueStore() const;
};
+
+ class DataRenderer: public CoreRefCountObject<BNDataRenderer, BNNewDataRendererReference, BNFreeDataRenderer>
+ {
+ static bool IsValidForDataCallback(void* ctxt, BNBinaryView* data, uint64_t addr, BNType* type,
+ BNType** typeCtx, size_t ctxCount);
+ static BNDisassemblyTextLine* GetLinesForDataCallback(void* ctxt, BNBinaryView* data, uint64_t addr, BNType* type,
+ const BNInstructionTextToken* prefix, size_t prefixCount, size_t width, size_t* count, BNType** typeCxt,
+ size_t ctxCount);
+ static void FreeCallback(void* ctxt);
+ public:
+ DataRenderer();
+ DataRenderer(BNDataRenderer* renderer);
+ virtual bool IsValidForData(BinaryView* data, uint64_t addr, Type* type, std::vector<Type*>& context);
+ virtual std::vector<DisassemblyTextLine> GetLinesForData(BinaryView* data, uint64_t addr, Type* type,
+ const std::vector<InstructionTextToken>& prefix, size_t width, std::vector<Type*>& context);
+
+ static bool IsStructOfTypeName(Type* type, const QualifiedName& name, std::vector<Type*>& context);
+ static bool IsStructOfTypeName(Type* type, const std::string& name, std::vector<Type*>& context);
+ };
+
+ class DataRendererContainer
+ {
+ public:
+ static void RegisterGenericDataRenderer(DataRenderer* renderer);
+ static void RegisterTypeSpecificDataRenderer(DataRenderer* renderer);
+ };
}
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 6dd5ae85..161a23af 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -156,6 +156,9 @@ extern "C"
struct BNSection;
struct BNRelocationInfo;
struct BNRelocationHandler;
+ struct BNDataBuffer;
+ struct BNDataRenderer;
+ struct BNDataRendererContainer;
typedef bool (*BNLoadPluginCallback)(const char* repoPath, const char* pluginPath, void* ctx);
@@ -1818,6 +1821,17 @@ extern "C"
void (*destructFunction)(void* ctxt, BNFunction* func);
};
+ struct BNCustomDataRenderer
+ {
+ void* context;
+ void (*freeObject)(void* ctxt);
+ bool (*isValidForData)(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type, BNType** typeCtx,
+ size_t ctxCount);
+ BNDisassemblyTextLine* (*getLinesForData)(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type,
+ const BNInstructionTextToken* prefix, size_t prefixCount, size_t width, size_t* count, BNType** typeCtx,
+ size_t ctxCount);
+ };
+
enum BNSegmentFlag
{
SegmentExecutable = 1,
@@ -3131,6 +3145,8 @@ extern "C"
BINARYNINJACOREAPI BNTypeWithConfidence BNGetMediumLevelILExprType(BNMediumLevelILFunction* func, size_t expr);
// Types
+ BINARYNINJACOREAPI bool BNTypesEqual(BNType* a, BNType* b);
+ BINARYNINJACOREAPI bool BNTypesNotEqual(BNType* a, BNType* b);
BINARYNINJACOREAPI BNType* BNCreateVoidType(void);
BINARYNINJACOREAPI BNType* BNCreateBoolType(void);
BINARYNINJACOREAPI BNType* BNCreateIntegerType(size_t width, BNBoolWithConfidence* sign, const char* altName);
@@ -3178,6 +3194,7 @@ extern "C"
BINARYNINJACOREAPI void BNTypeSetConst(BNType* type, BNBoolWithConfidence* cnst);
BINARYNINJACOREAPI void BNTypeSetVolatile(BNType* type, BNBoolWithConfidence* vltl);
BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeStackAdjustment(BNType* type);
+ BINARYNINJACOREAPI BNQualifiedName BNTypeGetStructureName(BNType* type);
BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform);
BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform);
@@ -3776,6 +3793,19 @@ extern "C"
BINARYNINJACOREAPI uint64_t BNSectionGetEntrySize(BNSection* section);
BINARYNINJACOREAPI BNSectionSemantics BNSectionGetSemantics(BNSection* section);
BINARYNINJACOREAPI bool BNSectionIsAutoDefined(BNSection* section);
+
+ // Custom Data Render methods
+ BINARYNINJACOREAPI BNDataRenderer* BNCreateDataRenderer(BNCustomDataRenderer* renderer);
+ BINARYNINJACOREAPI BNDataRenderer* BNNewDataRendererReference(BNDataRenderer* renderer);
+ BINARYNINJACOREAPI bool BNIsValidForData(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type,
+ BNType** typeCtx, size_t ctxCount);
+ BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetLinesForData(void* ctxt, BNBinaryView* view, uint64_t addr,
+ BNType* type, const BNInstructionTextToken* prefix, size_t prefixCount, size_t width, size_t* count,
+ BNType** typeCtx, size_t ctxCount);
+ BINARYNINJACOREAPI void BNFreeDataRenderer(BNDataRenderer* renderer);
+ BINARYNINJACOREAPI BNDataRendererContainer* BNGetDataRendererContainer();
+ BINARYNINJACOREAPI void BNRegisterGenericDataRenderer(BNDataRendererContainer* container, BNDataRenderer* renderer);
+ BINARYNINJACOREAPI void BNRegisterTypeSpecificDataRenderer(BNDataRendererContainer* container, BNDataRenderer* renderer);
#ifdef __cplusplus
}
#endif
diff --git a/datarenderer.cpp b/datarenderer.cpp
new file mode 100644
index 00000000..1fce92a7
--- /dev/null
+++ b/datarenderer.cpp
@@ -0,0 +1,184 @@
+#include "binaryninjaapi.h"
+
+using namespace std;
+using namespace BinaryNinja;
+
+
+DataRenderer::DataRenderer(BNDataRenderer* renderer)
+{
+ m_object = renderer;
+}
+
+
+DataRenderer::DataRenderer()
+{
+ BNCustomDataRenderer renderer;
+ renderer.context = this;
+ renderer.freeObject = FreeCallback;
+ renderer.isValidForData = IsValidForDataCallback;
+ renderer.getLinesForData = GetLinesForDataCallback;
+ AddRefForRegistration();
+ m_object = BNCreateDataRenderer(&renderer);
+}
+
+
+bool DataRenderer::IsStructOfTypeName(Type* type, const QualifiedName& name, vector<Type*>& context)
+{
+ return (type->GetClass() == StructureTypeClass) &&
+ (context.size() > 0) &&
+ (context[0]->GetClass() == NamedTypeReferenceClass) &&
+ (context[0]->GetNamedTypeReference()->GetName() == name);
+}
+
+
+bool DataRenderer::IsStructOfTypeName(Type* type, const string& name, vector<Type*>& context)
+{
+ return DataRenderer::IsStructOfTypeName(type, QualifiedName(name), context);
+}
+
+
+bool DataRenderer::IsValidForDataCallback(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type,
+ BNType** typeCtx, size_t ctxCount)
+{
+ DataRenderer* renderer = (DataRenderer*)ctxt;
+ Ref<BinaryView> viewObj = new BinaryView(BNNewViewReference(view));
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ vector<Type*> context;
+ context.reserve(ctxCount);
+ for (size_t i = 0; i < ctxCount; i++)
+ context.push_back(new Type(BNNewTypeReference(typeCtx[i])));
+
+ return renderer->IsValidForData(viewObj, addr, typeObj, context);
+}
+
+
+BNDisassemblyTextLine* DataRenderer::GetLinesForDataCallback(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type,
+ const BNInstructionTextToken* prefix, size_t prefixCount, size_t width, size_t* count, BNType** typeCtx,
+ size_t ctxCount)
+{
+ DataRenderer* renderer = (DataRenderer*)ctxt;
+ Ref<BinaryView> viewObj = new BinaryView(BNNewViewReference(view));
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ vector<InstructionTextToken> prefixes;
+ prefixes.reserve(prefixCount);
+ for (size_t i = 0; i < prefixCount; i++)
+ {
+ prefixes.emplace_back(prefix[i].type, prefix[i].context, prefix[i].text, prefix[i].address,
+ prefix[i].value, prefix[i].size, prefix[i].operand, prefix[i].confidence);
+ }
+ vector<Type*> context;
+ context.reserve(ctxCount);
+ for (size_t i = 0; i < ctxCount; i++)
+ context.push_back(new Type(BNNewTypeReference(typeCtx[i])));
+ auto lines = renderer->GetLinesForData(viewObj, addr, typeObj, prefixes, width, context);
+ *count = lines.size();
+ BNDisassemblyTextLine* buf = new BNDisassemblyTextLine[lines.size()];
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ const DisassemblyTextLine& line = lines[i];
+ buf[i].addr = line.addr;
+ buf[i].instrIndex = line.instrIndex;
+ buf[i].highlight = line.highlight;
+ buf[i].tokens = new BNInstructionTextToken[line.tokens.size()];
+ buf[i].count = line.tokens.size();
+ for (size_t j = 0; j < line.tokens.size(); j++)
+ {
+ const InstructionTextToken& token = line.tokens[j];
+ buf[i].tokens[j].type = token.type;
+ buf[i].tokens[j].text = BNAllocString(token.text.c_str());
+ buf[i].tokens[j].value = token.value;
+ buf[i].tokens[j].size = token.size;
+ buf[i].tokens[j].operand = token.operand;
+ buf[i].tokens[j].context = token.context;
+ buf[i].tokens[j].confidence = token.confidence;
+ buf[i].tokens[j].address = token.address;
+ }
+ }
+ return buf;
+}
+
+
+void DataRenderer::FreeCallback(void* ctxt)
+{
+ DataRenderer* renderer = (DataRenderer*)ctxt;
+ renderer->ReleaseForRegistration();
+}
+
+
+bool DataRenderer::IsValidForData(BinaryView* data, uint64_t addr, Type* type, vector<Type*>& context)
+{
+ BNType** typeCtx = new BNType*[context.size()];
+ for (size_t i = 0; i < context.size(); i++)
+ typeCtx[i] = context[i]->GetObject();
+ bool result = BNIsValidForData(m_object, data->GetObject(), addr, type->GetObject(), typeCtx, context.size());
+ delete[] typeCtx;
+ return result;
+}
+
+
+vector<DisassemblyTextLine> DataRenderer::GetLinesForData(BinaryView* data, uint64_t addr, Type* type,
+ const std::vector<InstructionTextToken>& prefix, size_t width, vector<Type*>& context)
+{
+ BNInstructionTextToken* prefixes = new BNInstructionTextToken[prefix.size()];
+ for (size_t i = 0; i < prefix.size(); i++)
+ {
+ prefixes[i].type = prefix[i].type;
+ prefixes[i].text = BNAllocString(prefix[i].text.c_str());
+ prefixes[i].value = prefix[i].value;
+ prefixes[i].size = prefix[i].size;
+ prefixes[i].operand = prefix[i].operand;
+ prefixes[i].context = prefix[i].context;
+ prefixes[i].confidence = prefix[i].confidence;
+ prefixes[i].address = prefix[i].address;
+ }
+ BNType** typeCtx = new BNType*[context.size()];
+ for (size_t i = 0; i < context.size(); i++)
+ typeCtx[i] = context[i]->GetObject();
+
+ size_t count = 0;
+ BNDisassemblyTextLine* lines = BNGetLinesForData(m_object, data->GetObject(), addr, type->GetObject(), prefixes,
+ prefix.size(), width, &count, typeCtx, context.size());
+
+ delete[] typeCtx;
+ for (size_t i = 0; i < prefix.size(); i++)
+ BNFreeString(prefixes[i].text);
+
+ delete[] prefixes;
+ vector<DisassemblyTextLine> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ DisassemblyTextLine line;
+ line.addr = lines[i].addr;
+ line.instrIndex = lines[i].instrIndex;
+ line.highlight = lines[i].highlight;
+ line.tokens.reserve(lines[i].count);
+ for (size_t j = 0; j < lines[i].count; j++)
+ {
+ InstructionTextToken token;
+ token.type = lines[i].tokens[j].type;
+ token.text = lines[i].tokens[j].text;
+ token.value = lines[i].tokens[j].value;
+ token.size = lines[i].tokens[j].size;
+ token.operand = lines[i].tokens[j].operand;
+ token.context = lines[i].tokens[j].context;
+ token.confidence = lines[i].tokens[j].confidence;
+ token.address = lines[i].tokens[j].address;
+ line.tokens.push_back(token);
+ }
+ result.push_back(line);
+ }
+ return result;
+}
+
+
+void DataRendererContainer::RegisterGenericDataRenderer(DataRenderer* renderer)
+{
+ BNRegisterGenericDataRenderer(BNGetDataRendererContainer(), renderer->GetObject());
+}
+
+
+void DataRendererContainer::RegisterTypeSpecificDataRenderer(DataRenderer* renderer)
+{
+ BNRegisterTypeSpecificDataRenderer(BNGetDataRendererContainer(), renderer->GetObject());
+} \ No newline at end of file
diff --git a/python/__init__.py b/python/__init__.py
index 2c6cb311..d2140f23 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -128,6 +128,7 @@ from binaryninja.pluginmanager import *
from binaryninja.settings import *
from binaryninja.metadata import *
from binaryninja.flowgraph import *
+from binaryninja.datarender import *
def shutdown():
diff --git a/python/datarender.py b/python/datarender.py
new file mode 100644
index 00000000..db60f42e
--- /dev/null
+++ b/python/datarender.py
@@ -0,0 +1,181 @@
+# Copyright (c) 2015-2017 Vector 35 LLC
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+
+import traceback
+import ctypes
+
+import binaryninja
+from binaryninja import _binaryninjacore as core
+from binaryninja.filemetadata import FileMetadata
+from binaryninja.binaryview import BinaryView
+from binaryninja.function import (DisassemblyTextLine, InstructionTextToken)
+from binaryninja.enums import InstructionTextTokenType, TypeClass, HighlightStandardColor
+from binaryninja.log import log_error
+from binaryninja.types import Type
+from binaryninja import highlight
+
+class DataRenderer(object):
+ """
+ DataRender objects tell the Linear View how to render specific types.
+
+ The `perform_is_valid_for_data` method returns a boolean to indicate if your derrived class
+ is able to render the type, given the `addr` and `context`. The `context` is a list of Type
+ objects which represents the chain of nested objects that is being displayed.
+
+ The `perform_get_lines_for_data` method returns a list of `DisassemblyTextLine` objects each one
+ representing a single line of Linear View output. The `prefix` variable is a list of `InstructionTextToken`'s
+ which have already been generated by other `DataRender`'s.
+
+ After defining the `DataRenderer` subclass you must then register it with the core. This is done by calling
+ either `register_type_sepcific` or `register_generic`. A "generic" type renderer is able to be overridden by
+ a "type specific" renderer. For instance there is a generic struct render which renders any struct that hasn't
+ been explicitly overridden by a "type specific" renderer.
+
+ In the below example we create a data renderer that overrides the default display for `struct BAR`.
+
+ class BarDataRenderer(DataRenderer):
+ def __init__(self):
+ DataRenderer.__init__(self)
+
+ def perform_is_valid_for_data(self, ctxt, view, addr, type, context):
+ return DataRenderer.is_type_of_struct_name(type, "BAR", context)
+
+ def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context):
+ prefix.append(InstructionTextToken(InstructionTextTokenType.TextToken, "I'm in ur BAR"))
+ return [DisassemblyTextLine(prefix, addr)]
+
+ def __del__(self):
+ pass
+
+ BarDataRenderer().register_type_sepcific()
+ """
+ def __init__(self, context=None):
+ self._cb = core.BNCustomDataRenderer()
+ self._cb.context = context
+ self._cb.freeObject = self._cb.freeObject.__class__(self._free_object)
+ self._cb.isValidForData = self._cb.isValidForData.__class__(self._is_valid_for_data)
+ self._cb.getLinesForData = self._cb.getLinesForData.__class__(self._get_lines_for_data)
+ self.handle = core.BNCreateDataRenderer(self._cb)
+
+ @classmethod
+ def is_type_of_struct_name(cls, type, name, context):
+ return (type.type_class == TypeClass.StructureTypeClass and len(context) > 0
+ and context[0].type_class == TypeClass.NamedTypeReferenceClass and
+ context[0].named_type_reference.name == name)
+
+ def register_type_sepcific(self):
+ core.BNRegisterTypeSpecificDataRenderer(core.BNGetDataRendererContainer(), self.handle)
+
+ def register_generic(self):
+ core.BNRegisterGenericDataRenderer(core.BNGetDataRendererContainer(), self.handle)
+
+ def _free_object(self, ctxt):
+ try:
+ self.perform_free_object(ctxt)
+ except:
+ log_error(traceback.format_exc())
+
+ def _is_valid_for_data(self, ctxt, view, addr, type, context, ctxCount):
+ try:
+ file_metadata = FileMetadata(handle=core.BNGetFileForView(view))
+ view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view))
+ type = Type(handle=core.BNNewTypeReference(type))
+ pycontext = []
+ for i in range(0, ctxCount):
+ pycontext.append(Type(core.BNNewTypeReference(context[i])))
+ return self.perform_is_valid_for_data(ctxt, view, addr, type, pycontext)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _get_lines_for_data(self, ctxt, view, addr, type, prefix, prefixCount, width, count, typeCtx, ctxCount):
+ try:
+ file_metadata = FileMetadata(handle=core.BNGetFileForView(view))
+ view = BinaryView(file_metadata=file_metadata, handle=core.BNNewViewReference(view))
+ type = Type(handle=core.BNNewTypeReference(type))
+
+ prefixTokens = []
+ for i in range(prefixCount):
+ token_type = InstructionTextTokenType(prefix[i].type)
+ text = prefix[i].text
+ value = prefix[i].value
+ size = prefix[i].size
+ operand = prefix[i].operand
+ context = prefix[i].context
+ address = prefix[i].address
+ confidence = prefix[i].confidence
+ prefixTokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+
+ pycontext = []
+ for i in range(ctxCount):
+ pycontext.append(Type(core.BNNewTypeReference(typeCtx[i])))
+
+ result = self.perform_get_lines_for_data(ctxt, view, addr, type, prefixTokens, width, pycontext)
+
+ count[0] = len(result)
+ line_buf = (core.BNDisassemblyTextLine * len(result))()
+ for i in range(len(result)):
+ line = result[i]
+ color = line.highlight
+ if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
+ raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
+ if isinstance(color, HighlightStandardColor):
+ color = highlight.HighlightColor(color)
+ line_buf[i].highlight = color._get_core_struct()
+ line_buf[i].count = len(line.tokens)
+ line_buf[i].tokens = (core.BNInstructionTextToken * len(line.tokens))()
+ if line.address is None:
+ if len(line.tokens) > 0:
+ line_buf[i].addr = line.tokens[0].address
+ else:
+ line_buf[i].addr = 0
+ else:
+ line_buf[i].addr = line.address
+ if line.il_instruction is not None:
+ line_buf[i].instrIndex = line.il_instruction.instr_index
+ else:
+ line_buf[i].instrIndex = 0xffffffffffffffff
+ for j in range(len(line.tokens)):
+ line_buf[i].tokens[j].type = line.tokens[j].type
+ line_buf[i].tokens[j].text = line.tokens[j].text
+ line_buf[i].tokens[j].value = line.tokens[j].value
+ line_buf[i].tokens[j].size = line.tokens[j].size
+ line_buf[i].tokens[j].operand = line.tokens[j].operand
+ line_buf[i].tokens[j].context = line.tokens[j].context
+ line_buf[i].tokens[j].confidence = line.tokens[j].confidence
+ line_buf[i].tokens[j].address = line.tokens[j].address
+
+ return ctypes.cast(line_buf, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ return None
+
+ def perform_free_object(self, ctxt):
+ pass
+
+ def perform_is_valid_for_data(self, ctxt, view, addr, type, context):
+ return False
+
+ def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context):
+ return []
+
+ def __del__(self):
+ pass
diff --git a/python/downloadprovider.py b/python/downloadprovider.py
index 5ce8cfce..53bd488a 100644
--- a/python/downloadprovider.py
+++ b/python/downloadprovider.py
@@ -58,7 +58,8 @@ class DownloadInstance(object):
def _destroy_instance(self, ctxt):
try:
- self.__class__._registered_instances.remove(self)
+ if self in self.__class__._registered_instances:
+ self.__class__._registered_instances.remove(self)
self.perform_destroy_instance()
except:
log.log_error(traceback.format_exc())
diff --git a/python/types.py b/python/types.py
index c7ebaf19..4de55700 100644
--- a/python/types.py
+++ b/python/types.py
@@ -266,12 +266,12 @@ class Type(object):
def __eq__(self, value):
if not isinstance(value, Type):
return False
- return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+ return core.BNTypesEqual(self.handle, value.handle)
def __ne__(self, value):
if not isinstance(value, Type):
return True
- return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+ return core.BNTypesNotEqual(self.handle, value.handle)
@property
def type_class(self):
@@ -300,6 +300,16 @@ class Type(object):
result = core.BNIsTypeConst(self.handle)
return BoolWithConfidence(result.value, confidence = result.confidence)
+ @const.setter
+ def const(self, value):
+ 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)
+
@property
def modified(self):
"""Whether type is modified (read-only)"""
diff --git a/type.cpp b/type.cpp
index 56bc3865..ef9036aa 100644
--- a/type.cpp
+++ b/type.cpp
@@ -441,6 +441,17 @@ Type::Type(BNType* type)
m_object = type;
}
+bool Type::operator==(const Type& other)
+{
+ return BNTypesEqual(m_object, other.m_object);
+}
+
+
+bool Type::operator!=(const Type& other)
+{
+ return BNTypesNotEqual(m_object, other.m_object);
+}
+
BNTypeClass Type::GetClass() const
{
@@ -964,6 +975,15 @@ Confidence<Ref<Type>> Type::WithConfidence(uint8_t conf)
}
+QualifiedName Type::GetStructureName() const
+{
+ BNQualifiedName name = BNTypeGetStructureName(m_object);
+ QualifiedName result = QualifiedName::FromAPIObject(&name);
+ BNFreeQualifiedName(&name);
+ return result;
+}
+
+
NamedTypeReference::NamedTypeReference(BNNamedTypeReference* nt)
{
m_object = nt;