summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2022-05-20 20:42:12 -0400
committerGlenn Smith <glenn@vector35.com>2022-05-25 14:22:45 -0400
commit0569365d79aaeb74aa134f52db13aa54f9619c56 (patch)
treeaaf8f0d9913c08336b761e1130418368bd930ee4 /python
parentf5715d76bb50fbaaaad450aecf9c192e8450e0d9 (diff)
Add BinaryView::ParseTypesFromSource for clang+typelibs
Diffstat (limited to 'python')
-rw-r--r--python/binaryview.py21
-rw-r--r--python/platform.py13
-rw-r--r--python/typeparser.py22
3 files changed, 42 insertions, 14 deletions
diff --git a/python/binaryview.py b/python/binaryview.py
index be4eab96..9093bcda 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -6190,13 +6190,15 @@ class BinaryView:
finally:
core.BNFreeQualifiedNameAndType(result)
- def parse_types_from_string(self, text: str) -> '_types.TypeParserResult':
+ def parse_types_from_string(self, text: str, options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None) -> '_types.TypeParserResult':
"""
``parse_types_from_string`` parses string containing C into a :py:Class:`TypeParserResult` objects. This API
unlike the :py:meth:`Platform.parse_types_from_source` allows the reference of types already defined
in the 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
:return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
:rtype: TypeParserResult
:Example:
@@ -6209,12 +6211,27 @@ class BinaryView:
if not isinstance(text, str):
raise ValueError("Source must be a string")
+ if options is None:
+ options = []
+ if include_dirs is None:
+ include_dirs = []
+
parse = core.BNTypeParserResult()
try:
+ options_cpp = (ctypes.c_char_p * len(options))()
+ for (i, s) in enumerate(options):
+ options_cpp[i] = core.cstr(s)
+
+ include_dirs_cpp = (ctypes.c_char_p * len(include_dirs))()
+ for (i, s) in enumerate(include_dirs):
+ include_dirs_cpp[i] = core.cstr(s)
+
errors = ctypes.c_char_p()
type_list = core.BNQualifiedNameList()
type_list.count = 0
- if not core.BNParseTypesString(self.handle, text, parse, errors, type_list):
+ if not core.BNParseTypesString(
+ self.handle, text, options_cpp, len(options), include_dirs_cpp,
+ len(include_dirs), parse, errors, type_list):
assert errors.value is not None, "core.BNParseTypesString returned errors set to None"
error_str = errors.value.decode("utf-8")
core.free_string(errors)
diff --git a/python/platform.py b/python/platform.py
index fc46882b..05cbaabf 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -26,6 +26,7 @@ from typing import List, Dict, Optional
import binaryninja
from . import _binaryninjacore as core
from . import types
+from . import typeparser
from . import callingconvention
from . import typelibrary
from . import architecture
@@ -411,8 +412,8 @@ class Platform(metaclass=_PlatformMetaClass):
:param include_dirs: optional list of string filename include directories
:type include_dirs: list(str)
:param str auto_type_source: optional source of types if used for automatically generated types
- :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
- :rtype: TypeParserResult
+ :return: :py:class:`BasicTypeParserResult` (a SyntaxError is thrown on parse error)
+ :rtype: BasicTypeParserResult
:Example:
>>> platform.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n')
@@ -453,7 +454,7 @@ class Platform(metaclass=_PlatformMetaClass):
name = types.QualifiedName._from_core_struct(parse.functions[i].name)
functions[name] = types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform=self)
core.BNFreeTypeParserResult(parse)
- return types.TypeParserResult(type_dict, variables, functions)
+ return typeparser.BasicTypeParserResult(type_dict, variables, functions)
def parse_types_from_source_file(self, filename, include_dirs: Optional[List[str]] = None, auto_type_source=None):
"""
@@ -464,8 +465,8 @@ class Platform(metaclass=_PlatformMetaClass):
:param include_dirs: optional list of string filename include directories
:type include_dirs: list(str)
:param str auto_type_source: optional source of types if used for automatically generated types
- :return: :py:class:`TypeParserResult` (a SyntaxError is thrown on parse error)
- :rtype: TypeParserResult
+ :return: :py:class:`BasicTypeParserResult` (a SyntaxError is thrown on parse error)
+ :rtype: BasicTypeParserResult
:Example:
>>> file = "/Users/binja/tmp.c"
@@ -506,7 +507,7 @@ class Platform(metaclass=_PlatformMetaClass):
name = types.QualifiedName._from_core_struct(parse.functions[i].name)
functions[name] = types.Type.create(core.BNNewTypeReference(parse.functions[i].type), platform=self)
core.BNFreeTypeParserResult(parse)
- return types.TypeParserResult(type_dict, variables, functions)
+ return typeparser.BasicTypeParserResult(type_dict, variables, functions)
@property
def arch(self):
diff --git a/python/typeparser.py b/python/typeparser.py
index f1dffe13..f4eba3cf 100644
--- a/python/typeparser.py
+++ b/python/typeparser.py
@@ -121,6 +121,16 @@ class ParsedType:
@dataclasses.dataclass(frozen=True)
+class BasicTypeParserResult:
+ types: Dict['types.QualifiedName', 'types.Type']
+ variables: Dict['types.QualifiedName', 'types.Type']
+ functions: Dict['types.QualifiedName', 'types.Type']
+
+ def __repr__(self):
+ return f"<types: {self.types}, variables: {self.variables}, functions: {self.functions}>"
+
+
+@dataclasses.dataclass(frozen=True)
class TypeParserResult:
types: Dict['types.QualifiedName', ParsedType]
variables: Dict['types.QualifiedName', ParsedType]
@@ -392,14 +402,14 @@ class TypeParser(metaclass=_TypeParserMetaclass):
return False
def preprocess_source(
- self, source: str, file_name: str, platform: platform.Platform,
+ 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]]:
raise NotImplementedError("Not implemented")
def parse_types_from_source(
- self, source: str, file_name: str, platform: platform.Platform,
+ 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,
auto_type_source: str = ""
@@ -407,7 +417,7 @@ class TypeParser(metaclass=_TypeParserMetaclass):
raise NotImplementedError("Not implemented")
def parse_type_string(
- self, source: str, platform: platform.Platform,
+ self, source: str, platform: 'platform.Platform',
existing_types: Optional[List[QualifiedNameTypeAndId]] = None
) -> Tuple[Optional[Tuple['types.QualifiedNameType', 'types.Type']], List[TypeParserError]]:
raise NotImplementedError("Not implemented")
@@ -416,7 +426,7 @@ class TypeParser(metaclass=_TypeParserMetaclass):
class CoreTypeParser(TypeParser):
def preprocess_source(
- self, source: str, file_name: str, platform: platform.Platform,
+ 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]]:
@@ -464,7 +474,7 @@ class CoreTypeParser(TypeParser):
return output, errors
def parse_types_from_source(
- self, source: str, file_name: str, platform: platform.Platform,
+ 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,
auto_type_source: str = ""
@@ -514,7 +524,7 @@ class CoreTypeParser(TypeParser):
def parse_type_string(
- self, source: str, platform: platform.Platform,
+ self, source: str, platform: 'platform.Platform',
existing_types: Optional[List[QualifiedNameTypeAndId]] = None
) -> Tuple[Optional[Tuple['types.QualifiedNameType', 'types.Type']], List[TypeParserError]]:
if existing_types is None: