summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2022-11-07 21:39:41 -0500
committerGlenn Smith <glenn@vector35.com>2022-11-11 16:11:48 -0500
commit1a565da676a7d1be45bfde1a5f40252838ccf5d8 (patch)
tree6f22e0dabb94d4a27960ddfc73bc3451071da3ee
parent14d91ab76f7bcee588bcbb7e89639adae90c9f62 (diff)
Convenience helpers for type parsing in c++
-rw-r--r--binaryninjaapi.h46
-rw-r--r--binaryninjacore.h2
-rw-r--r--binaryview.cpp21
-rw-r--r--typeparser.cpp91
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)
{