diff options
| author | Glenn Smith <glenn@vector35.com> | 2022-02-16 17:54:15 -0500 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2022-05-11 17:04:32 -0400 |
| commit | 09c85a868bad7e6e1b1b117eefc2c2aa9aaef4be (patch) | |
| tree | e2b298049cc02f7b41f182a8f52a9e678c84dbeb /python/types.py | |
| parent | 545fef9216559d08f58f7e20082b36352203a8cf (diff) | |
Clang+TypeParser APIs
Diffstat (limited to 'python/types.py')
| -rw-r--r-- | python/types.py | 157 |
1 files changed, 95 insertions, 62 deletions
diff --git a/python/types.py b/python/types.py index 65f58192..e00b3408 100644 --- a/python/types.py +++ b/python/types.py @@ -19,7 +19,7 @@ # IN THE SOFTWARE. import ctypes -from typing import Generator, List, Union, Mapping, Tuple, Optional, Iterable +from typing import Generator, List, Union, Mapping, Tuple, Optional, Iterable, Dict from dataclasses import dataclass import uuid from abc import abstractmethod @@ -28,7 +28,8 @@ from abc import abstractmethod from . import _binaryninjacore as core from .enums import ( StructureVariant, SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass, ReferenceType, VariableSourceType, - TypeReferenceType, MemberAccess, MemberScope, TypeDefinitionLineType, TokenEscapingType + TypeReferenceType, MemberAccess, MemberScope, TypeDefinitionLineType, TokenEscapingType, + NameType ) from . import callingconvention from . import function as _function @@ -37,6 +38,7 @@ from . import architecture from . import binaryview from . import platform as _platform from . import typelibrary +from . import typeparser QualifiedNameType = Union[Iterable[Union[str, bytes]], str, 'QualifiedName'] BoolWithConfidenceType = Union[bool, 'BoolWithConfidence'] @@ -47,6 +49,7 @@ EnumMembersType = Union[List[Tuple[str, int]], List[str], List['EnumerationMembe SomeType = Union['TypeBuilder', 'Type'] TypeContainer = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary'] NameSpaceType = Optional[Union[str, List[str], 'NameSpace']] +TypeParserResult = typeparser.TypeParserResult # The following are needed to prevent the type checker from getting # confused as we have member functions in `Type` named the same thing _int = int @@ -223,6 +226,27 @@ class TypeDefinitionLine: def __repr__(self): return f"<typeDefinitionLine {self.type}: {self}>" + @staticmethod + def _from_core_struct(struct: core.BNTypeDefinitionLine, platform: Optional[_platform.Platform] = None): + tokens = _function.InstructionTextToken._from_core_struct(struct.tokens, struct.count) + type_ = Type.create(handle=core.BNNewTypeReference(struct.type), platform=platform) + root_type = Type.create(handle=core.BNNewTypeReference(struct.rootType), platform=platform) + root_type_name = core.pyNativeStr(struct.rootTypeName) + return TypeDefinitionLine(struct.lineType, tokens, type_, root_type, root_type_name, + struct.offset, struct.fieldIndex) + + def _to_core_struct(self): + struct = core.BNTypeDefinitionLine() + struct.lineType = self.line_type + struct.tokens = _function.InstructionTextToken._get_core_struct(self.tokens) + struct.count = len(self.tokens) + struct.type = core.BNNewTypeReference(self.type.handle) + struct.rootType = core.BNNewTypeReference(self.root_type.handle) + struct.rootTypeName = self.root_type_name + struct.offset = self.offset + struct.fieldIndex = self.field_index + return struct + class CoreSymbol: def __init__(self, handle: core.BNSymbolHandle): @@ -888,7 +912,10 @@ class FunctionBuilder(TypeBuilder): cls, return_type: Optional[SomeType] = None, calling_convention: Optional['callingconvention.CallingConvention'] = None, params: Optional[ParamsType] = None, var_args: Optional[BoolWithConfidenceType] = None, stack_adjust: Optional[OffsetWithConfidenceType] = None, - platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence + platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence, + can_return: Optional[BoolWithConfidence] = None, reg_stack_adjust: Optional[Dict['architecture.RegisterName', OffsetWithConfidenceType]] = None, + return_regs: Optional[Union['RegisterSet', List['architecture.RegisterType']]] = None, + name_type: 'NameType' = NameType.NoNameType ) -> 'FunctionBuilder': param_buf = FunctionBuilder._to_core_struct(params) if return_type is None: @@ -904,11 +931,38 @@ class FunctionBuilder(TypeBuilder): conv_conf.convention = calling_convention.handle conv_conf.confidence = calling_convention.confidence + if reg_stack_adjust is None: + reg_stack_adjust = {} + reg_stack_adjust_regs = (ctypes.c_uint32 * len(reg_stack_adjust))() + reg_stack_adjust_values = (core.BNOffsetWithConfidence * len(reg_stack_adjust))() + + for i, (reg, adjust) in enumerate(reg_stack_adjust.items()): + reg_stack_adjust_regs[i] = reg + reg_stack_adjust_values[i].value = adjust.value + reg_stack_adjust_values[i].confidence = adjust.confidence + + return_regs_set = core.BNRegisterSetWithConfidence() + if return_regs is None or platform is None: + return_regs_set.count = 0 + return_regs_set.confidence = 0 + else: + return_regs_set.count = len(return_regs) + return_regs_set.confidence = 255 + return_regs_set.regs = (ctypes.c_uint32 * len(return_regs))() + + for i, reg in enumerate(return_regs): + return_regs_set[i] = platform.arch.get_reg_index(reg) + if var_args is None: vararg_conf = BoolWithConfidence.get_core_struct(False, 0) else: vararg_conf = BoolWithConfidence.get_core_struct(var_args, core.max_confidence) + if can_return is None: + can_return_conf = BoolWithConfidence.get_core_struct(True, 0) + else: + can_return_conf = BoolWithConfidence.get_core_struct(can_return, core.max_confidence) + if stack_adjust is None: stack_adjust_conf = OffsetWithConfidence.get_core_struct(0, 0) else: @@ -916,7 +970,9 @@ class FunctionBuilder(TypeBuilder): if params is None: params = [] handle = core.BNCreateFunctionTypeBuilder( - ret_conf, conv_conf, param_buf, len(params), vararg_conf, stack_adjust_conf + ret_conf, conv_conf, param_buf, len(params), vararg_conf, can_return_conf, stack_adjust_conf, + reg_stack_adjust_regs, reg_stack_adjust_values, len(reg_stack_adjust), + return_regs_set, name_type ) assert handle is not None, "BNCreateFunctionTypeBuilder returned None" return cls(handle, platform, confidence) @@ -1783,13 +1839,7 @@ class Type: assert core_lines is not None, "core.BNGetTypeLines returned None" lines = [] for i in range(count.value): - tokens = _function.InstructionTextToken._from_core_struct(core_lines[i].tokens, core_lines[i].count) - type_ = Type.create(handle=core.BNNewTypeReference(core_lines[i].type), platform=self._platform) - root_type = Type.create(handle=core.BNNewTypeReference(core_lines[i].rootType), platform=self._platform) - root_type_name = core.pyNativeStr(core_lines[i].rootTypeName) - line = TypeDefinitionLine(core_lines[i].lineType, tokens, type_, root_type, root_type_name, - core_lines[i].offset, core_lines[i].fieldIndex) - lines.append(line) + lines.append(TypeDefinitionLine._from_core_struct(core_lines[i])) core.BNFreeTypeDefinitionLineList(core_lines, count.value) return lines @@ -2448,7 +2498,10 @@ class FunctionType(Type): calling_convention: Optional['callingconvention.CallingConvention'] = None, variable_arguments: BoolWithConfidenceType = BoolWithConfidence(False), stack_adjust: OffsetWithConfidence = OffsetWithConfidence(0), platform: Optional['_platform.Platform'] = None, - confidence: int = core.max_confidence + confidence: int = core.max_confidence, + can_return: BoolWithConfidence = True, reg_stack_adjust: Optional[Dict['architecture.RegisterName', OffsetWithConfidenceType]] = None, + return_regs: Optional[Union['RegisterSet', List['architecture.RegisterType']]] = None, + name_type: 'NameType' = NameType.NoNameType ) -> 'FunctionType': if ret is None: ret = VoidType.create() @@ -2474,9 +2527,38 @@ class FunctionType(Type): else: _stack_adjust = OffsetWithConfidence.get_core_struct(stack_adjust, core.max_confidence) + + if reg_stack_adjust is None: + reg_stack_adjust = {} + reg_stack_adjust_regs = (ctypes.c_uint32 * len(reg_stack_adjust))() + reg_stack_adjust_values = (core.BNOffsetWithConfidence * len(reg_stack_adjust))() + + for i, (reg, adjust) in enumerate(reg_stack_adjust.items()): + reg_stack_adjust_regs[i] = reg + reg_stack_adjust_values[i].value = adjust.value + reg_stack_adjust_values[i].confidence = adjust.confidence + + return_regs_set = core.BNRegisterSetWithConfidence() + if return_regs is None or platform is None: + return_regs_set.count = 0 + return_regs_set.confidence = 0 + else: + return_regs_set.count = len(return_regs) + return_regs_set.confidence = 255 + return_regs_set.regs = (ctypes.c_uint32 * len(return_regs))() + + for i, reg in enumerate(return_regs): + return_regs_set[i] = platform.arch.get_reg_index(reg) + + _can_return = BoolWithConfidence.get_core_struct(can_return) + if params is None: + params = [] func_type = core.BNCreateFunctionType( - ret_conf, conv_conf, param_buf, len(params), _variable_arguments, _stack_adjust + ret_conf, conv_conf, param_buf, len(params), _variable_arguments, _can_return, _stack_adjust, + reg_stack_adjust_regs, reg_stack_adjust_values, len(reg_stack_adjust), + return_regs_set, name_type ) + assert func_type is not None, f"core.BNCreateFunctionType returned None {ret_conf} {conv_conf} {param_buf} {_variable_arguments} {_stack_adjust}" return cls(core.BNNewTypeReference(func_type), platform, confidence) @@ -2735,55 +2817,6 @@ class RegisterSet: @dataclass(frozen=True) -class TypeParserResult: - types: Mapping[QualifiedName, Type] - variables: Mapping[QualifiedName, Type] - functions: Mapping[QualifiedName, Type] - - def __repr__(self): - return f"<types: {self.types}, variables: {self.variables}, functions: {self.functions}>" - - -def preprocess_source(source: str, filename: Optional[str] = None, - include_dirs: Optional[List[str]] = None) -> Tuple[Optional[str], str]: - """ - ``preprocess_source`` run the C preprocessor on the given source or source filename. - - :param str source: source to pre-process - :param str filename: optional filename to pre-process - :param include_dirs: list of string directories to use as include directories. - :type include_dirs: list(str) - :return: returns a tuple of (preprocessed_source, error_string) - :rtype: tuple(str,str) - :Example: - - >>> source = "#define TEN 10\\nint x[TEN];\\n" - >>> preprocess_source(source) - ('#line 1 "input"\\n\\n#line 2 "input"\\n int x [ 10 ] ;\\n', '') - >>> - """ - if filename is None: - filename = "input" - if include_dirs is None: - include_dirs = [] - dir_buf = (ctypes.c_char_p * len(include_dirs))() - for i in range(0, len(include_dirs)): - dir_buf[i] = include_dirs[i].encode('charmap') - output = ctypes.c_char_p() - errors = ctypes.c_char_p() - result = core.BNPreprocessSource(source, filename, output, errors, dir_buf, len(include_dirs)) - assert output.value is not None - assert errors.value is not None - output_str = output.value.decode('utf-8') - error_str = errors.value.decode('utf-8') - core.free_string(output) - core.free_string(errors) - if result: - return output_str, error_str - return None, error_str - - -@dataclass(frozen=True) class TypeFieldReference: func: Optional['_function.Function'] arch: Optional['architecture.Architecture'] |
