// Copyright (c) 2015-2023 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; for (size_t i = 0; i < count; ++i) { result.emplace_back(parsers[i]); } BNFreeStringList(parsers, count); return result; } vector DebugInfo::GetTypes(const string& parserName) const { size_t count; BNNameAndType* nameAndTypes = BNGetDebugTypes(m_object, parserName.size() == 0 ? nullptr : parserName.c_str(), &count); vector result; 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); vector result; for (size_t i = 0; i < count; ++i) { 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 Platform(BNNewPlatformReference(functions[i].platform)) : nullptr); } BNFreeDebugFunctions(functions, count); return result; } vector DebugInfo::GetDataVariables(const string& parserName) const { size_t count; BNDataVariableAndName* variableAndNames = BNGetDebugDataVariables(m_object, parserName.size() == 0 ? nullptr : parserName.c_str(), &count); vector result; for (size_t i = 0; i < count; ++i) { result.emplace_back(variableAndNames[i].address, Confidence(new Type(BNNewTypeReference(variableAndNames[i].type)), variableAndNames[i].typeConfidence), variableAndNames[i].autoDiscovered, variableAndNames[i].name); } BNFreeDataVariablesAndName(variableAndNames, 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 = BNGetDebugDataVariableByName(m_object, parserName.c_str(), name.c_str()); if (result) { BNFreeString(result->name); return {{result->address, Ref(new Type(result->type))}}; } return {}; } optional>> DebugInfo::GetDataVariableByAddress( const string& parserName, const uint64_t address) const { BNDataVariableAndName* nameAndVar = BNGetDebugDataVariableByAddress(m_object, parserName.c_str(), address); if (nameAndVar) { const tuple> result = {nameAndVar->name, Ref(new Type(nameAndVar->type))}; BNFreeString(nameAndVar->name); return {result}; } return {}; } // The tuple is (DebugInfoParserName, type) vector>> DebugInfo::GetTypesByName(const string& name) const { size_t count; BNNameAndType* namesAndTypes = BNGetDebugTypesByName(m_object, name.c_str(), &count); vector>> result; 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); vector>> result; 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); vector>> result; 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) { return BNAddDebugType(m_object, name.c_str(), type->GetObject()); } bool DebugInfo::AddFunction(const DebugFunctionInfo& function) { BNDebugFunctionInfo* input = new BNDebugFunctionInfo(); 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; bool result = BNAddDebugFunction(m_object, input); BNFreeString(input->shortName); BNFreeString(input->fullName); BNFreeString(input->rawName); return result; } bool DebugInfo::AddDataVariable(uint64_t address, Ref type, const string& name) { if (name.size() == 0) return BNAddDebugDataVariable(m_object, address, type->GetObject(), nullptr); return BNAddDebugDataVariable(m_object, address, type->GetObject(), name.c_str()); } ///////////////////// // 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; 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; 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 existingDebugInfo, std::function 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(), existingDebugInfo->GetObject(), ProgressCallback, &ctxt); if (!info) return nullptr; info = BNNewDebugInfoReference(info); } else { info = BNParseDebugInfo(m_object, view->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, bool (*progress)(void*, size_t, size_t), void* progressCtxt) { CustomDebugInfoParser* parser = (CustomDebugInfoParser*)ctxt; return parser->ParseInfo(new DebugInfo(debugInfo), new BinaryView(view), [=](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))) {}