#include "binaryninjaapi.h" #include "ffi.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; renderer.freeLines = FreeLinesCallback; AddRefForRegistration(); m_object = BNCreateDataRenderer(&renderer); } bool DataRenderer::IsStructOfTypeName(Type* type, const QualifiedName& name, vector>& context) { return (type->GetClass() == StructureTypeClass) && (context.size() > 0) && (context[context.size() - 1].first->GetClass() == NamedTypeReferenceClass) && (context[context.size() - 1].first->GetNamedTypeReference()->GetName() == name); } bool DataRenderer::IsStructOfTypeName(Type* type, const string& name, vector>& context) { return DataRenderer::IsStructOfTypeName(type, QualifiedName(name), context); } bool DataRenderer::IsValidForDataCallback( void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type, BNTypeContext* typeCtx, size_t ctxCount) { CallbackRef renderer(ctxt); Ref viewObj = new BinaryView(BNNewViewReference(view)); Ref typeObj = new Type(BNNewTypeReference(type)); vector> context; context.reserve(ctxCount); for (size_t i = 0; i < ctxCount; i++) { // To keep API compatibility we have to manually do the refcounting here Type* contextType = new Type(BNNewTypeReference(typeCtx[i].type)); contextType->AddRef(); context.push_back({contextType, typeCtx[i].offset}); } bool result = renderer->IsValidForData(viewObj, addr, typeObj, context); for (size_t i = 0; i < ctxCount; i++) context[i].first->Release(); return result; } BNDisassemblyTextLine* DataRenderer::GetLinesForDataCallback(void* ctxt, BNBinaryView* view, uint64_t addr, BNType* type, const BNInstructionTextToken* prefix, size_t prefixCount, size_t width, size_t* count, BNTypeContext* typeCtx, size_t ctxCount, const char* language) { CallbackRef renderer(ctxt); Ref viewObj = new BinaryView(BNNewViewReference(view)); Ref typeObj = new Type(BNNewTypeReference(type)); vector prefixes = InstructionTextToken::ConvertInstructionTextTokenList(prefix, prefixCount); vector> context; context.reserve(ctxCount); for (size_t i = 0; i < ctxCount; i++) { // To keep API compatibility we have to manually do the refcounting here Type* contextType = new Type(BNNewTypeReference(typeCtx[i].type)); contextType->AddRef(); context.push_back({contextType, typeCtx[i].offset}); } auto lines = renderer->GetLinesForData(viewObj, addr, typeObj, prefixes, width, context, language ? language : string()); BNDisassemblyTextLine* result = AllocAPIObjectList(lines, count); for (size_t i = 0; i < ctxCount; i++) context[i].first->Release(); return result; } void DataRenderer::FreeCallback(void* ctxt) { DataRenderer* renderer = (DataRenderer*)ctxt; renderer->ReleaseForRegistration(); } void DataRenderer::FreeLinesCallback(void* ctxt, BNDisassemblyTextLine* lines, size_t count) { FreeAPIObjectList(lines, count); } bool DataRenderer::IsValidForData(BinaryView* data, uint64_t addr, Type* type, vector>& context) { BNTypeContext* typeCtx = new BNTypeContext[context.size()]; for (size_t i = 0; i < context.size(); i++) { typeCtx[i].type = context[i].first->GetObject(); typeCtx[i].offset = context[i].second; } bool result = BNIsValidForData(m_object, data->GetObject(), addr, type->GetObject(), typeCtx, context.size()); delete[] typeCtx; return result; } vector DataRenderer::GetLinesForData(BinaryView* data, uint64_t addr, Type* type, const std::vector& prefix, size_t width, vector>& context, const string& language) { BNInstructionTextToken* prefixes = InstructionTextToken::CreateInstructionTextTokenList(prefix); BNTypeContext* typeCtx = new BNTypeContext[context.size()]; for (size_t i = 0; i < context.size(); i++) { typeCtx[i].type = context[i].first->GetObject(); typeCtx[i].offset = context[i].second; } size_t count = 0; BNDisassemblyTextLine* lines = BNGetLinesForData(m_object, data->GetObject(), addr, type->GetObject(), prefixes, prefix.size(), width, &count, typeCtx, context.size(), language.c_str()); delete[] typeCtx; for (size_t i = 0; i < prefix.size(); i++) { BNFreeString(prefixes[i].text); for (size_t j = 0; j < prefixes[j].namesCount; j++) BNFreeString(prefixes[i].typeNames[j]); delete[] prefixes[i].typeNames; } delete[] prefixes; vector result = ParseAPIObjectList(lines, count); BNFreeDisassemblyTextLines(lines, count); return result; } vector DataRenderer::RenderLinesForData(BinaryView* data, uint64_t addr, Type* type, const std::vector& prefix, size_t width, vector>& context, const string& language) { BNInstructionTextToken* prefixes = InstructionTextToken::CreateInstructionTextTokenList(prefix); BNTypeContext* typeCtx = new BNTypeContext[context.size()]; for (size_t i = 0; i < context.size(); i++) { typeCtx[i].type = context[i].first->GetObject(); typeCtx[i].offset = context[i].second; } size_t count = 0; BNDisassemblyTextLine* lines = BNRenderLinesForData( data->GetObject(), addr, type->GetObject(), prefixes, prefix.size(), width, &count, typeCtx, context.size(), language.c_str()); delete[] typeCtx; for (size_t i = 0; i < prefix.size(); i++) { BNFreeString(prefixes[i].text); for (size_t j = 0; j < prefixes[j].namesCount; j++) BNFreeString(prefixes[i].typeNames[j]); delete[] prefixes[i].typeNames; } delete[] prefixes; vector result = ParseAPIObjectList(lines, count); BNFreeDisassemblyTextLines(lines, count); return result; } void DataRendererContainer::RegisterGenericDataRenderer(DataRenderer* renderer) { BNRegisterGenericDataRenderer(BNGetDataRendererContainer(), renderer->GetObject()); } void DataRendererContainer::RegisterTypeSpecificDataRenderer(DataRenderer* renderer) { BNRegisterTypeSpecificDataRenderer(BNGetDataRendererContainer(), renderer->GetObject()); }