diff options
Diffstat (limited to 'python/typeparser.py')
| -rw-r--r-- | python/typeparser.py | 70 |
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, |
