summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/typeparser.py70
1 files changed, 69 insertions, 1 deletions
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,