diff options
| author | Glenn Smith <glenn@vector35.com> | 2023-02-20 21:58:55 -0500 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2023-11-06 16:10:47 -0500 |
| commit | 4108964609171327618627477163339656037111 (patch) | |
| tree | 79f4c6da6394b973cee05cc42b6edd7e2e20909d /python | |
| parent | b270d7ebe1e2a406e1f7f14807987d24b0c4a846 (diff) | |
Type Containers
Diffstat (limited to 'python')
| -rw-r--r-- | python/__init__.py | 1 | ||||
| -rw-r--r-- | python/binaryview.py | 18 | ||||
| -rw-r--r-- | python/debuginfo.py | 5 | ||||
| -rw-r--r-- | python/platform.py | 11 | ||||
| -rw-r--r-- | python/typecontainer.py | 246 | ||||
| -rw-r--r-- | python/typelibrary.py | 12 | ||||
| -rw-r--r-- | python/typeprinter.py | 30 | ||||
| -rw-r--r-- | python/types.py | 28 |
8 files changed, 319 insertions, 32 deletions
diff --git a/python/__init__.py b/python/__init__.py index 4a9d1d1c..2fddefe4 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -69,6 +69,7 @@ from .secretsprovider import * from .typeparser import * from .typeprinter import * from .component import * +from .typecontainer import * # We import each of these by name to prevent conflicts between # log.py and the function 'log' which we don't import below from .log import ( diff --git a/python/binaryview.py b/python/binaryview.py index cd7a0cdf..d7d2a2a8 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -71,6 +71,7 @@ from . import function as _function from . import types as _types from . import platform as _platform from . import deprecation +from . import typecontainer PathType = Union[str, os.PathLike] InstructionsType = Generator[Tuple[List['_function.InstructionTextToken'], int], None, None] @@ -1745,7 +1746,7 @@ class TypeMapping(collections.abc.Mapping): # type: ignore def __del__(self): if core is not None and self._type_list is not None: - core.BNFreeTypeList(self._type_list, len(self)) + core.BNFreeTypeAndNameList(self._type_list, len(self)) def __getitem__(self, key): if self._type_cache is None: @@ -6958,6 +6959,21 @@ class BinaryView: raise ValueError(error_str) return variable.PossibleValueSet(self.arch, result) + @property + def type_container(self) -> 'typecontainer.TypeContainer': + container = core.BNGetAnalysisTypeContainer(self.handle) + return typecontainer.TypeContainer(handle=container) + + @property + def auto_type_container(self) -> 'typecontainer.TypeContainer': + container = core.BNGetAnalysisAutoTypeContainer(self.handle) + return typecontainer.TypeContainer(handle=container) + + @property + def user_type_container(self) -> 'typecontainer.TypeContainer': + container = core.BNGetAnalysisUserTypeContainer(self.handle) + return typecontainer.TypeContainer(handle=container) + def get_type_by_name(self, name: '_types.QualifiedNameType') -> Optional['_types.Type']: """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` diff --git a/python/debuginfo.py b/python/debuginfo.py index 1b9bc712..65f879ea 100644 --- a/python/debuginfo.py +++ b/python/debuginfo.py @@ -31,6 +31,7 @@ from . import types as _types from .log import log_error from . import binaryview from . import filemetadata +from . import typecontainer _debug_info_parsers = {} ProgressFuncType = Callable[[int, int], bool] @@ -303,6 +304,10 @@ class DebugInfo(object): core.BNFreeStringList(parsers, count.value) + def get_type_container(self, parser_name: str) -> 'typecontainer.TypeContainer': + """Returns a TypeContainer interface for one of the parsers in this DebugInfo""" + return typecontainer.TypeContainer(core.BNGetDebugInfoTypeContainer(self.handle, parser_name)) + def types_from_parser(self, name: Optional[str] = None) -> Iterator[Tuple[str, _types.Type]]: """Returns a generator of all types provided by a named DebugInfoParser""" count = ctypes.c_ulonglong(0) diff --git a/python/platform.py b/python/platform.py index e60f9a8f..2c4a26f6 100644 --- a/python/platform.py +++ b/python/platform.py @@ -30,6 +30,7 @@ from . import typeparser from . import callingconvention from . import typelibrary from . import architecture +from . import typecontainer class _PlatformMetaClass(type): @@ -262,7 +263,7 @@ class Platform(metaclass=_PlatformMetaClass): for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform=self) - core.BNFreeTypeList(type_list, count.value) + core.BNFreeTypeAndNameList(type_list, count.value) return result @property @@ -275,7 +276,7 @@ class Platform(metaclass=_PlatformMetaClass): for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform=self) - core.BNFreeTypeList(type_list, count.value) + core.BNFreeTypeAndNameList(type_list, count.value) return result @property @@ -288,7 +289,7 @@ class Platform(metaclass=_PlatformMetaClass): for i in range(0, count.value): name = types.QualifiedName._from_core_struct(type_list[i].name) result[name] = types.Type.create(core.BNNewTypeReference(type_list[i].type), platform=self) - core.BNFreeTypeList(type_list, count.value) + core.BNFreeTypeAndNameList(type_list, count.value) return result @property @@ -359,6 +360,10 @@ class Platform(metaclass=_PlatformMetaClass): result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr) return Platform(handle=result), new_addr.value + @property + def type_container(self) -> 'typecontainer.TypeContainer': + return typecontainer.TypeContainer(core.BNGetPlatformTypeContainer(self.handle)) + def get_type_by_name(self, name): name = types.QualifiedName(name)._to_core_struct() obj = core.BNGetPlatformTypeByName(self.handle, name) diff --git a/python/typecontainer.py b/python/typecontainer.py new file mode 100644 index 00000000..3f371213 --- /dev/null +++ b/python/typecontainer.py @@ -0,0 +1,246 @@ +# Copyright (c) 2015-2023 Vector 35 Inc +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +import ctypes +from typing import Optional, Mapping, Callable, List, Tuple + +# Binary Ninja components +import binaryninja +from . import _binaryninjacore as core +from . import types as ty_ +from . import platform +from . import typeparser +from . import enums + + +ProgressFuncType = Callable[[int, int], bool] + + +class TypeContainer: + def __init__(self, handle: core.BNTypeContainerHandle): + binaryninja._init_plugins() + self.handle: core.BNTypeContainerHandle = core.handle_of_type(handle, core.BNTypeContainer) + + def __del__(self): + if core is not None: + core.BNFreeTypeContainer(self.handle) + + def __repr__(self): + return f"<type container {self.name}>" + + @property + def id(self) -> str: + return core.BNTypeContainerGetId(self.handle) + + @property + def name(self) -> str: + return core.BNTypeContainerGetName(self.handle) + + @property + def container_type(self) -> 'enums.TypeContainerType': + return core.BNTypeContainerGetType(self.handle) + + @property + def mutable(self) -> bool: + return core.BNTypeContainerIsMutable(self.handle) + + @property + def platform(self) -> 'platform.Platform': + handle = core.BNTypeContainerGetPlatform(self.handle) + assert handle is not None + return platform.Platform(handle=handle) + + def add_types(self, types: Mapping['ty_.QualifiedNameType', 'ty_.Type'], progress_func: Optional[ProgressFuncType] = None) -> Optional[Mapping['ty_.QualifiedName', str]]: + api_names = (core.BNQualifiedName * len(types))() + api_types = (ctypes.POINTER(core.BNType) * len(types))() + for (i, (key, value)) in enumerate(types.items()): + api_names[i] = ty_.QualifiedName(key)._to_core_struct() + api_types[i] = value.handle + + if progress_func: + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: progress_func(cur, total)) + else: + progress_func_obj = ctypes.CFUNCTYPE( + ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong + )(lambda ctxt, cur, total: True) + + result_names = ctypes.POINTER(core.BNQualifiedName)() + result_ids = ctypes.POINTER(ctypes.c_char_p)() + result_count = ctypes.c_size_t(0) + + if not core.BNTypeContainerAddTypes(self.handle, api_names, api_types, len(types), progress_func_obj, None, result_names, result_ids, result_count): + return None + + result = {} + for i in range(result_count.value): + name = ty_.QualifiedName._from_core_struct(result_names[i]) + id = core.pyNativeStr(result_ids[i]) + result[name] = id + + core.BNFreeTypeNameList(result_names, result_count.value) + core.BNFreeStringList(result_ids, result_count.value) + return result + + def rename_type(self, type_id: str, new_name: 'ty_.QualifiedNameType') -> bool: + return core.BNTypeContainerRenameType(self.handle, type_id, ty_.QualifiedName(new_name)._to_core_struct()) + + def delete_type(self, type_id: str) -> bool: + return core.BNTypeContainerDeleteType(self.handle, type_id) + + def get_type_id(self, type_name: 'ty_.QualifiedNameType') -> Optional[str]: + result = ctypes.c_char_p() + if not core.BNTypeContainerGetTypeId(self.handle, ty_.QualifiedName(type_name)._to_core_struct(), result): + return None + return core.pyNativeStr(result.value) + + def get_type_name(self, type_id: str) -> Optional['ty_.QualifiedName']: + api_result = core.BNQualifiedName() + if not core.BNTypeContainerGetTypeName(self.handle, type_id, api_result): + return None + result = ty_.QualifiedName._from_core_struct(api_result) + core.BNFreeQualifiedName(api_result) + return result + + def get_type_by_id(self, type_id: str) -> Optional['ty_.Type']: + result = ctypes.POINTER(core.BNType)() + if not core.BNTypeContainerGetTypeById(self.handle, type_id, result): + return None + return ty_.Type(handle=result) + + @property + def types(self) -> Optional[Mapping[str, Tuple['ty_.QualifiedName', 'ty_.Type']]]: + result_names = ctypes.POINTER(core.BNQualifiedName)() + result_ids = ctypes.POINTER(ctypes.c_char_p)() + result_types = ctypes.POINTER(ctypes.POINTER(core.BNType))() + result_count = ctypes.c_size_t(0) + + if not core.BNTypeContainerGetTypes(self.handle, result_ids, result_names, result_types, result_count): + return None + + result = {} + for i in range(result_count.value): + name = ty_.QualifiedName._from_core_struct(result_names[i]) + id = core.pyNativeStr(result_ids[i]) + type = ty_.Type(handle=core.BNNewTypeReference(result_types[i])) + result[id] = (name, type) + + core.BNFreeTypeNameList(result_names, result_count.value) + core.BNFreeStringList(result_ids, result_count.value) + core.BNFreeTypeList(result_types, result_count.value) + return result + + def get_type_by_name(self, type_name: 'ty_.QualifiedNameType') -> Optional['ty_.Type']: + result = ctypes.POINTER(core.BNType)() + if not core.BNTypeContainerGetTypeByName(self.handle, ty_.QualifiedName(type_name)._to_core_struct(), result): + return None + return ty_.Type(handle=result) + + @property + def type_ids(self) -> Optional[List[str]]: + result_ids = ctypes.POINTER(ctypes.c_char_p)() + result_count = ctypes.c_size_t(0) + if not core.BNTypeContainerGetTypeIds(self.handle, result_ids, result_count): + return None + + result = [] + for i in range(result_count.value): + id = core.pyNativeStr(result_ids[i]) + result.append(id) + + core.BNFreeStringList(result_ids, result_count.value) + return result + + @property + def type_names(self) -> Optional[List['ty_.QualifiedName']]: + result_names = ctypes.POINTER(core.BNQualifiedName)() + result_count = ctypes.c_size_t(0) + if not core.BNTypeContainerGetTypeNames(self.handle, result_names, result_count): + return None + + result = [] + for i in range(result_count.value): + name = ty_.QualifiedName._from_core_struct(result_names[i]) + result.append(name) + + core.BNFreeTypeNameList(result_names, result_count.value) + return result + + @property + def type_names_and_ids(self) -> Optional[Mapping[str, 'ty_.QualifiedName']]: + result_names = ctypes.POINTER(core.BNQualifiedName)() + result_ids = ctypes.POINTER(ctypes.c_char_p)() + result_count = ctypes.c_size_t(0) + if not core.BNTypeContainerGetTypeNamesAndIds(self.handle, result_ids, result_names, result_count): + return None + + result = {} + for i in range(result_count.value): + name = ty_.QualifiedName._from_core_struct(result_names[i]) + id = core.pyNativeStr(result_ids[i]) + result[id] = name + + core.BNFreeTypeNameList(result_names, result_count.value) + core.BNFreeStringList(result_ids, result_count.value) + return result + + def parse_types_from_source(self, source: str, file_name: str, platform: 'platform.Platform', + options: Optional[List[str]] = None, include_dirs: Optional[List[str]] = None, + auto_type_source: str = "" + ) -> Tuple[Optional['typeparser.TypeParserResult'], List['typeparser.TypeParserError']]: + if options is None: + options = [] + if include_dirs is None: + include_dirs = [] + + 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) + + result_cpp = core.BNTypeParserResult() + errors_cpp = ctypes.POINTER(core.BNTypeParserError)() + error_count = ctypes.c_size_t() + + success = core.BNTypeContainerParseTypesFromSource( + self.handle, source, file_name, platform.handle, + options_cpp, len(options), + include_dirs_cpp, len(include_dirs), auto_type_source, + result_cpp, errors_cpp, error_count + ) + + if success: + result = typeparser.TypeParserResult._from_core_struct(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 + + diff --git a/python/typelibrary.py b/python/typelibrary.py index 53f3e8ef..364a458d 100644 --- a/python/typelibrary.py +++ b/python/typelibrary.py @@ -28,6 +28,7 @@ from . import types from . import metadata from . import platform from . import architecture +from . import typecontainer class TypeLibrary: @@ -227,7 +228,7 @@ class TypeLibrary: """ return core.BNFinalizeTypeLibrary(self.handle) - def query_metadata(self, key: str) -> Optional[metadata.Metadata]: + def query_metadata(self, key: str) -> Optional['metadata.MetadataValueType']: """ `query_metadata` retrieves a metadata associated with the given key stored in the type library @@ -281,6 +282,15 @@ class TypeLibrary: """ core.BNTypeLibraryRemoveMetadata(self.handle, key) + @property + def type_container(self) -> 'typecontainer.TypeContainer': + """ + `type_container` returns a TypeContainer interface for interacting with the type library. + + :return: TypeContainer interface + """ + return typecontainer.TypeContainer(core.BNGetTypeLibraryTypeContainer(self.handle)) + def add_named_object(self, name: 'types.QualifiedName', type: 'types.Type') -> None: """ `add_named_object` directly inserts a named object into the type library's object store. diff --git a/python/typeprinter.py b/python/typeprinter.py index d7af3087..d6bf579e 100644 --- a/python/typeprinter.py +++ b/python/typeprinter.py @@ -35,6 +35,7 @@ from . import platform as _platform from . import types from . import function as _function from . import binaryview +from . import typecontainer from .log import log_error from .enums import TokenEscapingType @@ -220,11 +221,11 @@ class TypePrinter(metaclass=_TypePrinterMetaclass): log_error(traceback.format_exc()) return False - def _get_type_lines(self, ctxt, type, data, name, line_width, collapsed, escaping, result, result_count): + def _get_type_lines(self, ctxt, type, container, name, line_width, collapsed, escaping, result, result_count): try: result_py = self.get_type_lines( types.Type.create(handle=core.BNNewTypeReference(type)), - binaryview.BinaryView(handle=core.BNNewViewReference(data)), + typecontainer.TypeContainer(handle=container), types.QualifiedName._from_core_struct(name.contents), line_width, collapsed, escaping) @@ -378,12 +379,12 @@ class TypePrinter(metaclass=_TypePrinterMetaclass): """ raise NotImplementedError() - def get_type_lines(self, type: types.Type, data: binaryview.BinaryView, name: types.QualifiedNameType, line_width = 80, collapsed = False, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> List[types.TypeDefinitionLine]: + def get_type_lines(self, type: types.Type, container: 'typecontainer.TypeContainer', name: types.QualifiedNameType, line_width = 80, collapsed = False, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType) -> List[types.TypeDefinitionLine]: """ Generate a multi-line representation of a type :param type: Type to print - :param data: Binary View in which the type is defined + :param container: Type Container containing the type and dependencies :param name: Name of the type :param line_width: Maximum width of lines, in characters :param collapsed: Whether to collapse structure/enum blocks @@ -488,31 +489,20 @@ class CoreTypePrinter(TypePrinter): core.free_string(result_cpp) return result - def get_type_lines(self, type: types.Type, data: binaryview.BinaryView, - name: types.QualifiedNameType, line_width = 80, collapsed = False, + def get_type_lines(self, type: types.Type, container: 'typecontainer.TypeContainer', + name: types.QualifiedNameType, + line_width = 80, collapsed = False, escaping: TokenEscapingType = TokenEscapingType.BackticksTokenEscapingType ) -> List[types.TypeDefinitionLine]: if not isinstance(name, types.QualifiedName): name = types.QualifiedName(name) count = ctypes.c_ulonglong() core_lines = ctypes.POINTER(core.BNTypeDefinitionLine)() - if not core.BNGetTypePrinterTypeLines(self.handle, type.handle, data.handle, name._to_core_struct(), line_width, collapsed, ctypes.c_int(escaping), core_lines, count): + if not core.BNGetTypePrinterTypeLines(self.handle, type.handle, container.handle, name._to_core_struct(), line_width, collapsed, ctypes.c_int(escaping), core_lines, count): raise RuntimeError("BNGetTypePrinterTypeLines returned False") lines = [] for i in range(count.value): - tokens = _function.InstructionTextToken._from_core_struct(core_lines[i].tokens, core_lines[i].count) - type_ = types.Type.create(handle=core.BNNewTypeReference(core_lines[i].type), platform=data.platform) - root_type = types.Type.create(handle=core.BNNewTypeReference(core_lines[i].rootType), platform=data.platform) - root_type_name = core.pyNativeStr(core_lines[i].rootTypeName) - if core_lines[i].baseType: - const_conf = types.BoolWithConfidence.get_core_struct(False, 0) - volatile_conf = types.BoolWithConfidence.get_core_struct(False, 0) - handle = core.BNCreateNamedTypeReference(core_lines[i].baseType, 0, 1, const_conf, volatile_conf) - base_type = types.NamedTypeReferenceType(handle, data.platform) - else: - base_type = None - line = types.TypeDefinitionLine(core_lines[i].lineType, tokens, type_, root_type, root_type_name, base_type, - core_lines[i].baseOffset, core_lines[i].offset, core_lines[i].fieldIndex) + line = types.TypeDefinitionLine._from_core_struct(core_lines[i], container.platform) lines.append(line) core.BNFreeTypeDefinitionLineList(core_lines, count.value) return lines diff --git a/python/types.py b/python/types.py index 96532a4d..9fbe7a93 100644 --- a/python/types.py +++ b/python/types.py @@ -37,6 +37,7 @@ from . import variable from . import architecture from . import binaryview from . import platform as _platform +from . import typecontainer from . import typelibrary from . import typeparser @@ -47,7 +48,7 @@ ParamsType = Union[List['Type'], List['FunctionParameter'], List[Tuple[str, 'Typ MembersType = Union[List['StructureMember'], List['Type'], List[Tuple['Type', str]]] EnumMembersType = Union[List[Tuple[str, int]], List[str], List['EnumerationMember']] SomeType = Union['TypeBuilder', 'Type'] -TypeContainer = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary'] +TypeContainerType = 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 @@ -515,7 +516,7 @@ class BoolWithConfidence: @dataclass class MutableTypeBuilder(Generic[TB]): type: TB - container: TypeContainer + container: TypeContainerType name: QualifiedName platform: Optional['_platform.Platform'] confidence: int @@ -601,7 +602,7 @@ class TypeBuilder: @classmethod def builder( - cls: typing.Type[TB], container: TypeContainer, name: 'QualifiedName', user: bool = True, platform: Optional['_platform.Platform'] = None, + cls: typing.Type[TB], container: TypeContainerType, name: 'QualifiedName', user: bool = True, platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence ) -> 'MutableTypeBuilder[TB]': return MutableTypeBuilder(cls.create(), container, name, platform, confidence, user) @@ -1997,7 +1998,7 @@ class Type: return result def get_lines( - self, bv: 'binaryview.BinaryView', name: str, line_width: int = 80, collapsed: bool = False, + self, bv: Union['binaryview.BinaryView', 'typecontainer.TypeContainer'], name: str, line_width: int = 80, collapsed: bool = False, escaping: TokenEscapingType = TokenEscapingType.NoTokenEscapingType ) -> List['TypeDefinitionLine']: """ @@ -2014,7 +2015,13 @@ class Type: :rtype: :py:class:`TypeDefinitionLine` """ count = ctypes.c_ulonglong() - core_lines = core.BNGetTypeLines(self._handle, bv.handle, name, line_width, collapsed, escaping, count) + if isinstance(bv, (binaryview.BinaryView,)): + container = bv.type_container + elif isinstance(bv, (typecontainer.TypeContainer,)): + container = bv + else: + assert False, "Unexpected type container type" + core_lines = core.BNGetTypeLines(self._handle, container.handle, name, line_width, collapsed, escaping, count) assert core_lines is not None, "core.BNGetTypeLines returned None" lines = [] for i in range(count.value): @@ -2526,10 +2533,17 @@ class StructureType(Type): def type(self) -> StructureVariant: return StructureVariant(core.BNGetStructureType(self.struct_handle)) - def members_including_inherited(self, view: 'binaryview.BinaryView') -> List[InheritedStructureMember]: + def members_including_inherited(self, view: Union['binaryview.BinaryView', 'typecontainer.TypeContainer']) -> List[InheritedStructureMember]: """Returns structure member list, including those inherited by base structures""" count = ctypes.c_ulonglong() - members = core.BNGetStructureMembersIncludingInherited(self.struct_handle, view.handle, count) + if isinstance(view, (binaryview.BinaryView,)): + container = view.type_container + elif isinstance(view, (typecontainer.TypeContainer,)): + container = view + else: + assert False, "Unexpected type container type" + + members = core.BNGetStructureMembersIncludingInherited(self.struct_handle, container.handle, count) assert members is not None, "core.BNGetInheritedStructureMembers returned None" try: result = [] |
