diff options
| author | Glenn Smith <glenn@vector35.com> | 2022-11-07 21:39:41 -0500 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2022-11-11 16:11:48 -0500 |
| commit | 1a565da676a7d1be45bfde1a5f40252838ccf5d8 (patch) | |
| tree | 6f22e0dabb94d4a27960ddfc73bc3451071da3ee | |
| parent | 14d91ab76f7bcee588bcbb7e89639adae90c9f62 (diff) | |
Convenience helpers for type parsing in c++
| -rw-r--r-- | binaryninjaapi.h | 46 | ||||
| -rw-r--r-- | binaryninjacore.h | 2 | ||||
| -rw-r--r-- | binaryview.cpp | 21 | ||||
| -rw-r--r-- | typeparser.cpp | 91 |
4 files changed, 159 insertions, 1 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index efebbfe7..b738c92a 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2805,6 +2805,7 @@ namespace BinaryNinja { class Metadata; class Structure; class NamedTypeReference; + struct ParsedType; struct TypeParserResult; class Component; class DebugInfo; @@ -4433,6 +4434,7 @@ namespace BinaryNinja { void DefineTypes(const std::vector<std::pair<std::string, QualifiedNameAndType>>& types, std::function<bool(size_t, size_t)> progress = {}); void DefineUserType(const QualifiedName& name, Ref<Type> type); void DefineUserTypes(const std::vector<QualifiedNameAndType>& types, std::function<bool(size_t, size_t)> progress = {}); + void DefineUserTypes(const std::vector<ParsedType>& types, std::function<bool(size_t, size_t)> progress = {}); void UndefineType(const std::string& id); void UndefineUserType(const QualifiedName& name); void RenameType(const QualifiedName& oldName, const QualifiedName& newName); @@ -6478,6 +6480,13 @@ namespace BinaryNinja { std::string fileName; uint64_t line; uint64_t column; + + TypeParserError() = default; + TypeParserError(BNTypeParserErrorSeverity severity, const std::string& message): + severity(severity), message(message), fileName(""), line(0), column(0) + { + + } }; /*! @@ -11561,6 +11570,20 @@ namespace BinaryNinja { static Ref<TypeParser> GetByName(const std::string& name); static Ref<TypeParser> GetDefault(); + /*! + Parse a space-separated string of options into a list + \param optionsText Space-separated options text + \return List of options + */ + static std::vector<std::string> ParseOptionsText(const std::string& optionsText); + + /*! + Format a list of parser errors into a big string + \param errors List of errors + \return String of formatted errors + */ + static std::string FormatParseErrors(const std::vector<TypeParserError>& errors); + /** Get the string representation of an option for passing to ParseTypes* \param option Option type @@ -11619,6 +11642,29 @@ namespace BinaryNinja { ) = 0; /*! + Parse an entire source file into types, variables, and functions + \param fileName Name of the file on disk containing the source + \param platform Platform to assume the types are relevant to + \param existingTypes Map of all existing types to use for parsing context + \param options String arguments to pass as options, e.g. command line arguments + \param includeDirs List of directories to include in the header search path + \param autoTypeSource Optional source of types if used for automatically generated types + \param result Reference to structure into which the results will be written + \param errors Reference to a list into which any parse errors will be written + \return True if parsing was successful + */ + bool ParseTypesFromSourceFile( + const std::string& fileName, + Ref<Platform> platform, + const std::map<QualifiedName, TypeAndId>& existingTypes, + const std::vector<std::string>& options, + const std::vector<std::string>& includeDirs, + const std::string& autoTypeSource, + TypeParserResult& result, + std::vector<TypeParserError>& errors + ); + + /*! Parse a single type and name from a string containing their definition. \param source Source code to parse \param platform Platform to assume the types are relevant to diff --git a/binaryninjacore.h b/binaryninjacore.h index f45fa675..c7530c22 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -5514,6 +5514,8 @@ extern "C" BNQualifiedNameAndType* result, BNTypeParserError** errors, size_t* errorCount ); + BINARYNINJACOREAPI char** BNParseTypeParserOptionsText(const char* optionsText, size_t* count); + BINARYNINJACOREAPI char* BNFormatTypeParserParseErrors(BNTypeParserError* errors, size_t count); BINARYNINJACOREAPI BNTypePrinter* BNRegisterTypePrinter( const char* name, BNTypePrinterCallbacks* callbacks); diff --git a/binaryview.cpp b/binaryview.cpp index e78333d5..e8c108a0 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -3565,6 +3565,27 @@ void BinaryView::DefineUserTypes(const vector<QualifiedNameAndType>& types, std: } +void BinaryView::DefineUserTypes(const vector<ParsedType>& types, std::function<bool(size_t, size_t)> progress) +{ + BNQualifiedNameAndType* apiTypes = new BNQualifiedNameAndType[types.size()]; + for (size_t i = 0; i < types.size(); i++) + { + apiTypes[i].name = types[i].name.GetAPIObject(); + apiTypes[i].type = types[i].type->GetObject(); + } + + ProgressContext cb; + cb.callback = progress; + BNDefineUserAnalysisTypes(m_object, apiTypes, types.size(), ProgressCallback, &cb); + + for (size_t i = 0; i < types.size(); i++) + { + QualifiedName::FreeAPIObject(&apiTypes[i].name); + } + delete [] apiTypes; +} + + void BinaryView::UndefineType(const string& id) { BNUndefineAnalysisType(m_object, id.c_str()); diff --git a/typeparser.cpp b/typeparser.cpp index c93c03b3..6124004c 100644 --- a/typeparser.cpp +++ b/typeparser.cpp @@ -1,8 +1,9 @@ #include "binaryninjaapi.h" +#include <filesystem> using namespace BinaryNinja; using namespace std; - +namespace fs = std::filesystem; TypeParser::TypeParser(const string& name) : m_nameForRegister(name) {} @@ -57,6 +58,48 @@ void TypeParser::Register(TypeParser* parser) } +std::vector<std::string> TypeParser::ParseOptionsText(const std::string& optionsText) +{ + size_t count; + char** options = BNParseTypeParserOptionsText(optionsText.c_str(), &count); + + std::vector<std::string> result; + for (size_t i = 0; i < count; i++) + { + result.push_back(options[i]); + } + + BNFreeStringList(options, count); + return result; +} + + +std::string TypeParser::FormatParseErrors(const std::vector<TypeParserError>& errors) +{ + std::vector<BNTypeParserError> apiErrors; + for (const auto& error: errors) + { + BNTypeParserError apiError; + apiError.severity = error.severity; + apiError.message = BNAllocString(error.message.c_str()); + apiError.fileName = BNAllocString(error.fileName.c_str()); + apiError.line = error.line; + apiError.column = error.column; + apiErrors.push_back(apiError); + } + + char* string = BNFormatTypeParserParseErrors(apiErrors.data(), apiErrors.size()); + + for (auto& apiError: apiErrors) + { + BNFreeString(apiError.message); + BNFreeString(apiError.fileName); + } + + return string; +} + + bool TypeParser::GetOptionText(BNTypeParserOption option, std::string value, std::string& result) const { // Default: Don't accept anything @@ -311,6 +354,52 @@ void TypeParser::FreeErrorListCallback(void* ctxt, BNTypeParserError* errors, si } +bool TypeParser::ParseTypesFromSourceFile(const string& fileName, Ref<Platform> platform, + const map<QualifiedName, TypeAndId>& existingTypes, const vector<string>& options, + const vector<string>& includeDirs, const string& autoTypeSource, TypeParserResult& result, + vector<TypeParserError>& errors) +{ + if (!fs::is_regular_file(fileName)) + { + errors.push_back(TypeParserError(FatalSeverity, string("error: argument '") + fileName + "' is not a file")); + return false; + } + + // Read file contents, then parse them + FILE* fp = fopen(fileName.c_str(), "rb"); + if (!fp) + { + errors.push_back(TypeParserError(FatalSeverity, string("file '") + fileName + "' not found")); + return false; + } + + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + if(size == -1) + { + errors.push_back(TypeParserError(FatalSeverity, string("error: unable to open '") + fileName)); + return false; + } + fseek(fp, 0, SEEK_SET); + + char* data = new char[size + 2]; + if (fread(data, 1, size, fp) != (size_t)size) + { + errors.push_back(TypeParserError(FatalSeverity, string("error: file '") + fileName + "' could not be read")); + delete[] data; + fclose(fp); + return false; + } + data[size++] = '\n'; + data[size] = 0; + fclose(fp); + + bool ok = ParseTypesFromSource(data, fileName, platform, existingTypes, options, includeDirs, autoTypeSource, result, errors); + delete[] data; + return ok; +} + + CoreTypeParser::CoreTypeParser(BNTypeParser* parser): TypeParser(parser) { |
