From 6955825444658317609313782745220062335525 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Tue, 2 Apr 2024 13:33:19 -0400 Subject: Add `importDependencies` argument to `ParseTypeString` to control library imports --- python/binaryview.py | 12 +++++++----- python/typecontainer.py | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) (limited to 'python') diff --git a/python/binaryview.py b/python/binaryview.py index 933bc12c..0f1f77c2 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -7026,7 +7026,7 @@ class BinaryView: return iter(LinearDisassemblyIterator(self, settings)) - def parse_type_string(self, text: str) -> Tuple['_types.Type', '_types.QualifiedName']: + def parse_type_string(self, text: str, import_dependencies: bool = True) -> Tuple['_types.Type', '_types.QualifiedName']: """ ``parse_type_string`` parses string containing C into a single type :py:class:`Type`. In contrast to the :py:func:`~binaryninja.platform.Platform.parse_types_from_source` or :py:func:`~binaryninja.platform.Platform.parse_types_from_source_file`, ``parse_type_string`` @@ -7034,6 +7034,7 @@ class BinaryView: view, while those two APIs do not. :param str text: C source code string of type to create + :param import_dependencies: If Type Library / Type Archive types should be imported during parsing :return: A tuple of a :py:class:`Type` and type name :rtype: tuple(Type, QualifiedName) :Example: @@ -7050,7 +7051,7 @@ class BinaryView: errors = ctypes.c_char_p() type_list = core.BNQualifiedNameList() type_list.count = 0 - if not core.BNParseTypeString(self.handle, text, result, errors, type_list): + if not core.BNParseTypeString(self.handle, text, result, errors, type_list, import_dependencies): assert errors.value is not None, "core.BNParseTypeString returned 'errors' set to None" error_str = errors.value.decode("utf-8") core.free_string(errors) @@ -7061,7 +7062,7 @@ class BinaryView: finally: core.BNFreeQualifiedNameAndType(result) - def parse_types_from_string(self, text: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None) -> '_types.TypeParserResult': + def parse_types_from_string(self, text: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None, import_dependencies: bool = True) -> '_types.TypeParserResult': """ ``parse_types_from_string`` parses string containing C into a :py:class:`TypeParserResult` objects. This API unlike the :py:func:`~binaryninja.platform.Platform.parse_types_from_source` allows the reference of types already defined @@ -7070,6 +7071,7 @@ class BinaryView: :param str text: C source code string of types, variables, and function types, to create :param options: Optional list of string options to be passed into the type parser :param include_dirs: Optional list of header search directories + :param import_dependencies: If Type Library / Type Archive types should be imported during parsing :return: :py:class:`~binaryninja.typeparser.TypeParserResult` (a SyntaxError is thrown on parse error) :rtype: TypeParserResult :Example: @@ -7102,7 +7104,7 @@ class BinaryView: type_list.count = 0 if not core.BNParseTypesString( self.handle, text, options_cpp, len(options), include_dirs_cpp, - len(include_dirs), parse, errors, type_list): + len(include_dirs), parse, errors, type_list, import_dependencies): assert errors.value is not None, "core.BNParseTypesString returned errors set to None" error_str = errors.value.decode("utf-8") core.free_string(errors) @@ -7170,7 +7172,7 @@ class BinaryView: value = '' if not core.BNParsePossibleValueSet(self.handle, value, state, result, here, errors): if errors: - assert errors.value is not None, "core.BNParseTypesString returned errors set to None" + assert errors.value is not None, "core.BNParsePossibleValueSet returned errors set to None" error_str = errors.value.decode("utf-8") else: error_str = "Error parsing specified PossibleValueSet" diff --git a/python/typecontainer.py b/python/typecontainer.py index a0e35f2d..cc1b3288 100644 --- a/python/typecontainer.py +++ b/python/typecontainer.py @@ -300,9 +300,46 @@ class TypeContainer: core.BNFreeStringList(result_ids, result_count.value) return result + def parse_type_string( + self, source: str, import_dependencies: bool = True + ) -> Tuple[Optional[Tuple['_types.QualifiedNameType', '_types.Type']], List['typeparser.TypeParserError']]: + """ + Parse a single type and name from a string containing their definition, with + knowledge of the types in the Type Container. + + :param source: Source code to parse + :param import_dependencies: If Type Library / Type Archive types should be imported during parsing + :return: A tuple of (result, errors) where result is a tuple of (type, name) or + None of there was a fatal error. + """ + result_cpp = core.BNQualifiedNameAndType() + errors_cpp = ctypes.POINTER(core.BNTypeParserError)() + error_count = ctypes.c_size_t() + + success = core.BNTypeContainerParseTypeString( + self.handle, source, import_dependencies, result_cpp, errors_cpp, error_count + ) + + if success: + result = ( + _types.QualifiedName._from_core_struct(result_cpp.name), + _types.Type.create(handle=core.BNNewTypeReference(result_cpp.type)) + ) + core.BNFreeQualifiedNameAndType(result_cpp) + else: + result = None + core.BNFreeTypeParserResult(result_cpp) + + errors = [] + for i in range(error_count.value): + errors.append(typeparser.TypeParserError._from_core_struct(errors_cpp[i])) + core.BNFreeTypeParserErrors(errors_cpp, error_count.value) + + return result, errors + def parse_types_from_source(self, source: str, file_name: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None, - auto_type_source: str = "" + auto_type_source: str = "", import_dependencies: bool = True ) -> Tuple[Optional['typeparser.TypeParserResult'], List['typeparser.TypeParserError']]: """ Parse an entire block of source into types, variables, and functions, with @@ -313,6 +350,7 @@ class TypeContainer: :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 + :param import_dependencies: If Type Library / Type Archive types should be imported during parsing :return: A tuple of (result, errors) where the result is None if there was a fatal error """ if options is None: @@ -335,7 +373,7 @@ class TypeContainer: success = core.BNTypeContainerParseTypesFromSource( self.handle, source, file_name, options_cpp, len(options), - include_dirs_cpp, len(include_dirs), auto_type_source, + include_dirs_cpp, len(include_dirs), auto_type_source, import_dependencies, result_cpp, errors_cpp, error_count ) -- cgit v1.3.1