summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h12
-rw-r--r--binaryninjacore.h13
-rw-r--r--python/typeparser.py70
-rw-r--r--typeparser.cpp33
4 files changed, 125 insertions, 3 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index a6a98da2..efebbfe7 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -11529,6 +11529,7 @@ namespace BinaryNinja {
explicit TypeParser(const std::string& name);
TypeParser(BNTypeParser* parser);
+ static bool GetOptionTextCallback(void* ctxt, BNTypeParserOption option, const char* value, char** result);
static bool PreprocessSourceCallback(void* ctxt,
const char* source, const char* fileName, BNPlatform* platform,
const BNQualifiedNameTypeAndId* existingTypes, size_t existingTypeCount,
@@ -11560,6 +11561,15 @@ namespace BinaryNinja {
static Ref<TypeParser> GetByName(const std::string& name);
static Ref<TypeParser> GetDefault();
+ /**
+ Get the string representation of an option for passing to ParseTypes*
+ \param option Option type
+ \param value Option value
+ \param result String representing the option
+ \return True if the parser supports the option
+ */
+ virtual bool GetOptionText(BNTypeParserOption option, std::string value, std::string& result) const;
+
/*!
Preprocess a block of source, returning the source that would be parsed
\param source Source code to process
@@ -11635,6 +11645,8 @@ namespace BinaryNinja {
CoreTypeParser(BNTypeParser* parser);
virtual ~CoreTypeParser() {}
+ virtual bool GetOptionText(BNTypeParserOption option, std::string value, std::string& result) const override;
+
virtual bool PreprocessSource(
const std::string& source,
const std::string& fileName,
diff --git a/binaryninjacore.h b/binaryninjacore.h
index cb9a83c4..f45fa675 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -36,14 +36,14 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
-#define BN_CURRENT_CORE_ABI_VERSION 27
+#define BN_CURRENT_CORE_ABI_VERSION 28
// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
// will require rebuilding. The minimum version is increased when there are
// incompatible changes that break binary compatibility, such as changes to
// existing types or functions.
-#define BN_MINIMUM_CORE_ABI_VERSION 24
+#define BN_MINIMUM_CORE_ABI_VERSION 28
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -2104,6 +2104,12 @@ extern "C"
BNLowLevelILFunction* il, BNRelocation* relocation);
};
+ enum BNTypeParserOption
+ {
+ IncludeSystemTypes,
+ BuiltinMacros,
+ };
+
struct BNParsedType
{
BNQualifiedName name;
@@ -2515,6 +2521,7 @@ extern "C"
struct BNTypeParserCallbacks
{
void* context;
+ bool (*getOptionText)(void* ctxt, BNTypeParserOption option, const char* value, char** result);
bool (*preprocessSource)(void* ctxt,
const char* source, const char* fileName, BNPlatform* platform,
const BNQualifiedNameTypeAndId* existingTypes, size_t existingTypeCount,
@@ -5484,6 +5491,8 @@ extern "C"
BINARYNINJACOREAPI char* BNGetTypeParserName(BNTypeParser* parser);
+ BINARYNINJACOREAPI bool BNGetTypeParserOptionText(BNTypeParser* parser, BNTypeParserOption option,
+ const char* value, char** result);
BINARYNINJACOREAPI bool BNTypeParserPreprocessSource(BNTypeParser* parser,
const char* source, const char* fileName, BNPlatform* platform,
const BNQualifiedNameTypeAndId* existingTypes, size_t existingTypeCount,
diff --git a/python/typeparser.py b/python/typeparser.py
index b6ea0c59..1b8fe57a 100644
--- a/python/typeparser.py
+++ b/python/typeparser.py
@@ -35,7 +35,7 @@ from .settings import Settings
from . import platform
from . import types
from .log import log_error
-from .enums import TypeParserErrorSeverity
+from .enums import TypeParserErrorSeverity, TypeParserOption
@dataclasses.dataclass(frozen=True)
@@ -199,6 +199,10 @@ class _TypeParserMetaclass(type):
@property
def default(self):
+ """
+ Get the default parser as specified by the user's settings
+ :return: Default parser
+ """
name = binaryninja.Settings().get_string("analysis.types.parserName")
return CoreTypeParser[name]
@@ -216,10 +220,14 @@ class TypeParser(metaclass=_TypeParserMetaclass):
self.__dict__["name"] = core.BNGetTypeParserName(handle)
def register(self):
+ """
+ Register a custom parser with the API
+ """
assert self.__class__.name is not None
self._cb = core.BNTypeParserCallbacks()
self._cb.context = 0
+ self._cb.getOptionText = self._cb.getOptionText.__class__(self._get_option_text)
self._cb.preprocessSource = self._cb.preprocessSource.__class__(self._preprocess_source)
self._cb.parseTypesFromSource = self._cb.parseTypesFromSource.__class__(self._parse_types_from_source)
self._cb.parseTypeString = self._cb.parseTypeString.__class__(self._parse_type_string)
@@ -235,6 +243,19 @@ class TypeParser(metaclass=_TypeParserMetaclass):
def __repr__(self):
return f'<TypeParser: {self.name}>'
+ def _get_option_text(self, option, value, result) -> bool:
+ try:
+ value_py = core.pyNativeStr(value)
+ result_py = self.get_option_text(option, value_py)
+ if result_py is None:
+ return False
+ TypeParser._cached_string = core.cstr(result_py)
+ result[0] = TypeParser._cached_string
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
def _preprocess_source(
self, ctxt, source, fileName, platform_, existingTypes, existingTypeCount,
options, optionCount, includeDirs, includeDirCount,
@@ -401,11 +422,31 @@ class TypeParser(metaclass=_TypeParserMetaclass):
log_error(traceback.format_exc())
return False
+ def get_option_text(self, option: TypeParserOption, value: str) -> Optional[str]:
+ """
+ Get the string representation of an option for passing to parse_type_*
+ :param option: Option type
+ :param value: Option value
+ :return: A string representing the option if the parser supports it, otherwise None
+ """
+ return None
+
def preprocess_source(
self, source: str, file_name: str, platform: 'platform.Platform',
existing_types: Optional[List[QualifiedNameTypeAndId]] = None,
options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None
) -> Tuple[Optional[str], List[TypeParserError]]:
+ """
+ Preprocess a block of source, returning the source that would be parsed
+ :param source: Source code to process
+ :param file_name: Name of the file containing the source (does not need to exist on disk)
+ :param platform: Platform to assume the source is relevant to
+ :param existing_types: Optional map of all existing types to use for parsing context
+ :param options: Optional string arguments to pass as options, e.g. command line arguments
+ :param include_dirs: Optional list of directories to include in the header search path
+ :return: A tuple of (preproccessed source, errors), where the preproccessed source
+ is None if there was a fatal error.
+ """
raise NotImplementedError("Not implemented")
def parse_types_from_source(
@@ -414,17 +455,44 @@ class TypeParser(metaclass=_TypeParserMetaclass):
options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None,
auto_type_source: str = ""
) -> Tuple[Optional[TypeParserResult], List[TypeParserError]]:
+ """
+ Parse an entire block of source into types, variables, and functions
+ :param source: Source code to parse
+ :param file_name: Name of the file containing the source (optional: exists on disk)
+ :param platform: Platform to assume the types are relevant to
+ :param existing_types: Optional map of all existing types to use for parsing context
+ :param options: Optional string arguments to pass as options, e.g. command line arguments
+ :param include_dirs: Optional list of directories to include in the header search path
+ :param auto_type_source: Optional source of types if used for automatically generated types
+ :return: A tuple of (result, errors) where the result is None if there was a fatal error
+ """
raise NotImplementedError("Not implemented")
def parse_type_string(
self, source: str, platform: 'platform.Platform',
existing_types: Optional[List[QualifiedNameTypeAndId]] = None
) -> Tuple[Optional[Tuple['types.QualifiedNameType', 'types.Type']], List[TypeParserError]]:
+ """
+ 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
+ :param existing_types: Optional map of all existing types to use for parsing context
+ :return: A tuple of (result, errors) where result is a tuple of (type, name) or
+ None of there was a fatal error.
+ """
raise NotImplementedError("Not implemented")
class CoreTypeParser(TypeParser):
+ def get_option_text(self, option: TypeParserOption, value: str) -> Optional[str]:
+ result_cpp = ctypes.c_char_p()
+ if not core.BNGetTypeParserOptionText(self.handle, option, value, result_cpp):
+ return None
+ result = core.pyNativeStr(result_cpp.value)
+ core.free_string(result_cpp)
+ return result
+
def preprocess_source(
self, source: str, file_name: str, platform: 'platform.Platform',
existing_types: Optional[List[QualifiedNameTypeAndId]] = None,
diff --git a/typeparser.cpp b/typeparser.cpp
index 8351de2f..c93c03b3 100644
--- a/typeparser.cpp
+++ b/typeparser.cpp
@@ -46,6 +46,7 @@ void TypeParser::Register(TypeParser* parser)
{
BNTypeParserCallbacks cb;
cb.context = parser;
+ cb.getOptionText = GetOptionTextCallback;
cb.preprocessSource = PreprocessSourceCallback;
cb.parseTypesFromSource = ParseTypesFromSourceCallback;
cb.parseTypeString = ParseTypeStringCallback;
@@ -56,6 +57,27 @@ void TypeParser::Register(TypeParser* parser)
}
+bool TypeParser::GetOptionText(BNTypeParserOption option, std::string value, std::string& result) const
+{
+ // Default: Don't accept anything
+ return false;
+}
+
+
+bool TypeParser::GetOptionTextCallback(void* ctxt, BNTypeParserOption option, const char* value,
+ char** result)
+{
+ TypeParser* parser = (TypeParser*)ctxt;
+ string resultCpp;
+ if (!parser->GetOptionText(option, value, resultCpp))
+ {
+ return false;
+ }
+ *result = BNAllocString(resultCpp.c_str());
+ return true;
+}
+
+
bool TypeParser::PreprocessSourceCallback(void* ctxt,
const char* source, const char* fileName, BNPlatform* platform,
const BNQualifiedNameTypeAndId* existingTypes, size_t existingTypeCount,
@@ -295,6 +317,17 @@ CoreTypeParser::CoreTypeParser(BNTypeParser* parser): TypeParser(parser)
}
+bool CoreTypeParser::GetOptionText(BNTypeParserOption option, std::string value, std::string& result) const
+{
+ char* apiResult;
+ if (!BNGetTypeParserOptionText(m_object, option, value.c_str(), &apiResult))
+ return false;
+ result = apiResult;
+ BNFreeString(apiResult);
+ return true;
+}
+
+
bool CoreTypeParser::PreprocessSource(const std::string& source, 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,