// Copyright (c) 2015-2026 Vector 35 Inc // // 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. // TODO : Documentation #include "binaryninjaapi.h" using namespace BinaryNinja; using namespace std; /////////////// // DebugInfo // /////////////// DebugInfo::DebugInfo(BNDebugInfo* debugInfo) { m_object = debugInfo; } vector DebugInfo::GetParsers() const { size_t count; char** parsers = BNGetDebugParserNames(m_object, &count); vector result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(parsers[i]); } BNFreeStringList(parsers, count); return result; } TypeContainer DebugInfo::GetTypeContainer(const std::string& parserName) { return TypeContainer(BNGetDebugInfoTypeContainer(m_object, parserName.c_str())); } vector DebugInfo::GetTypes(const string& parserName) const { size_t count; BNNameAndType* nameAndTypes = BNGetDebugTypes(m_object, parserName.size() == 0 ? nullptr : parserName.c_str(), &count); if (nameAndTypes == nullptr) return {}; vector result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(nameAndTypes[i].name, Confidence>(new Type(BNNewTypeReference(nameAndTypes[i].type)), nameAndTypes[i].typeConfidence)); } BNFreeDebugTypes(nameAndTypes, count); return result; } vector DebugInfo::GetFunctions(const string& parserName) const { size_t count; BNDebugFunctionInfo* functions = BNGetDebugFunctions(m_object, parserName.size() == 0 ? nullptr : parserName.c_str(), &count); if (functions == nullptr) return {}; vector result; result.reserve(count); for (size_t i = 0; i < count; ++i) { vector components; components.reserve(functions[i].componentN); for (size_t componentN = 0; componentN < functions[i].componentN; ++componentN) components.emplace_back(functions[i].components[componentN]); vector localVariables; localVariables.reserve(functions[i].localVariableN); for (size_t localVariableN = 0; localVariableN < functions[i].localVariableN; ++localVariableN) { auto& bnVar = functions[i].localVariables[localVariableN]; VariableNameAndType vnt; vnt.var = bnVar.var; vnt.name = bnVar.name; vnt.autoDefined = bnVar.autoDefined; vnt.type = Confidence>(new Type(BNNewTypeReference(bnVar.type)), bnVar.typeConfidence); localVariables.push_back(vnt); } result.emplace_back(functions[i].shortName ? functions[i].shortName : "", functions[i].fullName ? functions[i].fullName : "", functions[i].rawName ? functions[i].rawName : "", functions[i].address, functions[i].type ? new Type(BNNewTypeReference(functions[i].type)) : nullptr, functions[i].platform ? new CorePlatform(BNNewPlatformReference(functions[i].platform)) : nullptr, components, localVariables); } BNFreeDebugFunctions(functions, count); return result; } vector DebugInfo::GetDataVariables(const string& parserName) const { size_t count; BNDataVariableAndName* variablesAndName = BNGetDebugDataVariables(m_object, parserName.size() == 0 ? nullptr : parserName.c_str(), &count); if (variablesAndName == nullptr) return {}; vector result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(variablesAndName[i].address, Confidence(new Type(BNNewTypeReference(variablesAndName[i].type)), variablesAndName[i].typeConfidence), variablesAndName[i].autoDiscovered, variablesAndName[i].name); } BNFreeDataVariablesAndName(variablesAndName, count); return result; } // May return nullptr Ref DebugInfo::GetTypeByName(const string& parserName, const string& name) const { BNType* result = BNGetDebugTypeByName(m_object, parserName.c_str(), name.c_str()); if (result) return Ref(new Type(result)); return nullptr; } optional>> DebugInfo::GetDataVariableByName( const string& parserName, const string& name) const { BNDataVariableAndName result; if (!BNGetDebugDataVariableByName(m_object, parserName.c_str(), name.c_str(), &result)) return std::nullopt; Ref type = new Type(BNNewTypeReference(result.type)); BNFreeDataVariableAndName(&result); return {{result.address, type}}; } optional>> DebugInfo::GetDataVariableByAddress( const string& parserName, const uint64_t address) const { BNDataVariableAndName result; if (!BNGetDebugDataVariableByAddress(m_object, parserName.c_str(), address, &result)) return std::nullopt; string name = result.name; Ref type = new Type(BNNewTypeReference(result.type)); BNFreeDataVariableAndName(&result); return {{name, type}}; } // The tuple is (DebugInfoParserName, type) vector>> DebugInfo::GetTypesByName(const string& name) const { size_t count; BNNameAndType* namesAndTypes = BNGetDebugTypesByName(m_object, name.c_str(), &count); if (namesAndTypes == nullptr) return {}; vector>> result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(namesAndTypes[i].name, Ref(new Type(BNNewTypeReference(namesAndTypes[i].type)))); } BNFreeNameAndTypeList(namesAndTypes, count); return result; } // The tuple is (DebugInfoParserName, address, type) vector>> DebugInfo::GetDataVariablesByName(const string& name) const { size_t count; BNDataVariableAndName* variablesAndName = BNGetDebugDataVariablesByName(m_object, name.c_str(), &count); if (variablesAndName == nullptr) return {}; vector>> result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(variablesAndName[i].name, variablesAndName[i].address, Ref(new Type(BNNewTypeReference(variablesAndName[i].type)))); } BNFreeDataVariablesAndName(variablesAndName, count); return result; } // The tuple is (DebugInfoParserName, TypeName, type) vector>> DebugInfo::GetDataVariablesByAddress(const uint64_t address) const { size_t count; BNDataVariableAndNameAndDebugParser* variablesAndName = BNGetDebugDataVariablesByAddress(m_object, address, &count); if (variablesAndName == nullptr) return {}; vector>> result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(variablesAndName[i].parser, variablesAndName[i].name, Ref(new Type(BNNewTypeReference(variablesAndName[i].type)))); } BNFreeDataVariableAndNameAndDebugParserList(variablesAndName, count); return result; } bool DebugInfo::RemoveParserInfo(const string& parserName) { return BNRemoveDebugParserInfo(m_object, parserName.c_str()); } bool DebugInfo::RemoveParserTypes(const string& parserName) { return BNRemoveDebugParserTypes(m_object, parserName.c_str()); } bool DebugInfo::RemoveParserFunctions(const string& parserName) { return BNRemoveDebugParserFunctions(m_object, parserName.c_str()); } bool DebugInfo::RemoveParserDataVariables(const string& parserName) { return BNRemoveDebugParserDataVariables(m_object, parserName.c_str()); } bool DebugInfo::RemoveTypeByName(const string& parserName, const string& name) { return BNRemoveDebugTypeByName(m_object, parserName.c_str(), name.c_str()); } bool DebugInfo::RemoveFunctionByIndex(const string& parserName, const size_t index) { return BNRemoveDebugFunctionByIndex(m_object, parserName.c_str(), index); } bool DebugInfo::RemoveDataVariableByAddress(const string& parserName, const uint64_t address) { return BNRemoveDebugDataVariableByAddress(m_object, parserName.c_str(), address); } bool DebugInfo::AddType(const string& name, Ref type, const vector& components) { const char** const componentArray = new const char*[components.size()]; for (size_t i = 0; i < components.size(); ++i) componentArray[i] = components[i].c_str(); bool result = BNAddDebugType(m_object, name.c_str(), type->GetObject(), componentArray, components.size()); delete[] componentArray; return result; } bool DebugInfo::AddFunction(const DebugFunctionInfo& function) { char** components = new char*[function.components.size()]; for (size_t i = 0; i < function.components.size(); ++i) components[i] = (char*)function.components[i].c_str(); BNVariableNameAndType* localVariables = new BNVariableNameAndType[function.localVariables.size()]; for (size_t i = 0; i < function.localVariables.size(); i++) { auto v = function.localVariables[i]; localVariables[i].var = v.var; localVariables[i].type = v.type.GetValue()->m_object; localVariables[i].typeConfidence = v.type.GetConfidence(); localVariables[i].name = (char*)v.name.c_str(); localVariables[i].autoDefined = v.autoDefined; } BNDebugFunctionInfo input; input.shortName = function.shortName.size() ? BNAllocString(function.shortName.c_str()) : nullptr; input.fullName = function.fullName.size() ? BNAllocString(function.fullName.c_str()) : nullptr; input.rawName = function.rawName.size() ? BNAllocString(function.rawName.c_str()) : nullptr; input.address = function.address; input.type = function.type ? function.type->GetObject() : nullptr; input.platform = function.platform ? function.platform->GetObject() : nullptr; input.components = components; input.componentN = function.components.size(); input.localVariables = localVariables; input.localVariableN = function.localVariables.size(); bool result = BNAddDebugFunction(m_object, &input); BNFreeString(input.shortName); BNFreeString(input.fullName); BNFreeString(input.rawName); delete[] components; delete[] localVariables; return result; } bool DebugInfo::AddDataVariable(uint64_t address, Ref type, const string& name, const vector& components) { const char** const componentArray = new const char*[components.size()]; for (size_t i = 0; i < components.size(); ++i) componentArray[i] = components[i].c_str(); if (name.size() == 0) return BNAddDebugDataVariable(m_object, address, type->GetObject(), nullptr, componentArray, components.size()); return BNAddDebugDataVariable(m_object, address, type->GetObject(), name.c_str(), componentArray, components.size()); } ///////////////////// // DebugInfoParser // ///////////////////// DebugInfoParser::DebugInfoParser(BNDebugInfoParser* parser) { m_object = parser; } Ref DebugInfoParser::GetByName(const string& name) { BNDebugInfoParser* parser = BNGetDebugInfoParserByName(name.c_str()); if (parser) return new DebugInfoParser(BNNewDebugInfoParserReference(parser)); return nullptr; } vector> DebugInfoParser::GetList() { size_t count = 0; BNDebugInfoParser** parsers = BNGetDebugInfoParsers(&count); vector> result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(new DebugInfoParser(BNNewDebugInfoParserReference(parsers[i]))); } BNFreeDebugInfoParserList(parsers, count); return result; } vector> DebugInfoParser::GetListForView(const Ref data) { size_t count = 0; BNDebugInfoParser** parsers = BNGetDebugInfoParsersForView(data->GetObject(), &count); vector> result; result.reserve(count); for (size_t i = 0; i < count; ++i) { result.emplace_back(new DebugInfoParser(BNNewDebugInfoParserReference(parsers[i]))); } BNFreeDebugInfoParserList(parsers, count); return result; } string DebugInfoParser::GetName() const { return BNGetDebugInfoParserName(m_object); } Ref DebugInfoParser::Parse(Ref view, Ref debugFile, Ref existingDebugInfo, ProgressFunction progress) const { ProgressContext ctxt; if (progress) ctxt.callback = progress; else ctxt.callback = [=](size_t, size_t) { return true; }; BNDebugInfo* info = nullptr; if (existingDebugInfo) { info = BNParseDebugInfo(m_object, view->GetObject(), debugFile->GetObject(), existingDebugInfo->GetObject(), ProgressCallback, &ctxt); if (!info) return nullptr; info = BNNewDebugInfoReference(info); } else { info = BNParseDebugInfo(m_object, view->GetObject(), debugFile->GetObject(), nullptr, ProgressCallback, &ctxt); if (!info) return nullptr; } return new DebugInfo(info); } bool DebugInfoParser::IsValidForView(const Ref view) const { return BNIsDebugInfoParserValidForView(m_object, view->GetObject()); } ////////////////////////////// // Plugin registration APIs // ////////////////////////////// bool CustomDebugInfoParser::IsValidCallback(void* ctxt, BNBinaryView* view) { CustomDebugInfoParser* parser = (CustomDebugInfoParser*)ctxt; return parser->IsValid(new BinaryView(view)); } bool CustomDebugInfoParser::ParseCallback(void* ctxt, BNDebugInfo* debugInfo, BNBinaryView* view, BNBinaryView* debugFile, BNProgressFunction progress, void* progressCtxt) { CustomDebugInfoParser* parser = (CustomDebugInfoParser*)ctxt; return parser->ParseInfo(new DebugInfo(debugInfo), new BinaryView(view), new BinaryView(debugFile), [=](size_t cur, size_t max) { return progress(progressCtxt, cur, max); }); } CustomDebugInfoParser::CustomDebugInfoParser(const string& name) : DebugInfoParser( BNNewDebugInfoParserReference(BNRegisterDebugInfoParser(name.c_str(), IsValidCallback, ParseCallback, this))) {}