Source code for binaryninja.platform

# Copyright (c) 2015-2025 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 os
import ctypes
import traceback
import warnings
from typing import List, Dict, Optional, Tuple

# Binary Ninja components
import binaryninja
from . import _binaryninjacore as core
from . import types
from . import typeparser
from . import callingconvention
from . import typelibrary
from . import architecture
from . import typecontainer
from . import binaryview
from .log import log_error


class _PlatformMetaClass(type):
	def __iter__(self):
		binaryninja._init_plugins()
		count = ctypes.c_ulonglong()
		platforms = core.BNGetPlatformList(count)
		assert platforms is not None, "core.BNGetPlatformList returned None"
		try:
			for i in range(0, count.value):
				yield CorePlatform(handle=core.BNNewPlatformReference(platforms[i]))
		finally:
			core.BNFreePlatformList(platforms, count.value)

	def __getitem__(cls, value):
		binaryninja._init_plugins()
		platform = core.BNGetPlatformByName(str(value))
		if platform is None:
			raise KeyError("'%s' is not a valid platform" % str(value))
		return CorePlatform(handle=platform)


[docs] class Platform(metaclass=_PlatformMetaClass): """ ``class Platform`` contains all information related to the execution environment of the binary, mainly the calling conventions used, the operating system, and the architecture. The following example showing the live list of platforms may not match your list. Some platforms are included only with specific versions of Binary Ninja and others are installed by plugins. The bare architecture version of the platform does not include any default ABI/calling convention:: >>> list(Platform) [<platform: Solana>, <platform: decree-x86>, <platform: efi-aarch64>, <platform: efi-windows-aarch64>, <platform: efi-x86>, <platform: efi-windows-x86>, <platform: efi-x86_64>, <platform: efi-windows-x86_64>, <platform: efi-armv7>, <platform: efi-thumb2>, <platform: freebsd-aarch64>, <platform: freebsd-x86>, <platform: freebsd-x86_64>, <platform: freebsd-armv7>, <platform: freebsd-thumb2>, <platform: ios-aarch64>, <platform: ios-armv7>, <platform: ios-thumb2>, <platform: ios-kernel-aarch64>, <platform: ios-kernel-armv7>, <platform: ios-kernel-thumb2>, <platform: linux-aarch64>, <platform: linux-mcore_le>, <platform: linux-mcore_be>, <platform: linux-csky_le_v1>, <platform: linux-csky_le>, <platform: linux-armv7eb>, <platform: linux-thumb2eb>, <platform: linux-mips>, <platform: linux-mipsel>, <platform: linux-mips3>, <platform: linux-mipsel3>, <platform: linux-mips64>, <platform: linux-cnmips64>, <platform: linux-ppc32>, <platform: linux-ppc64>, <platform: linux-ppc32_le>, <platform: linux-ppc64_le>, <platform: linux-rv32gc>, <platform: linux-rv64gc>, <platform: linux-x86>, <platform: linux-x86_64>, <platform: linux-armv7>, <platform: linux-thumb2>, <platform: mac-aarch64>, <platform: mac-x86>, <platform: mac-x86_64>, <platform: mac-armv7>, <platform: mac-thumb2>, <platform: mac-kernel-aarch64>, <platform: mac-kernel-x86>, <platform: mac-kernel-x86_64>, <platform: mac-kernel-armv7>, <platform: mac-kernel-thumb2>, <platform: vxworks-aarch64>, <platform: vxworks-mips32>, <platform: vxworks-mipsel32>, <platform: vxworks-mips64>, <platform: vxworks-cavium-mips64>, <platform: vxworks-ppc32>, <platform: vxworks-ppc64>, <platform: vxworks-rv32gc>, <platform: vxworks-rv64gc>, <platform: vxworks-x86>, <platform: vxworks-x86_64>, <platform: vxworks-armv7>, <platform: vxworks-thumb2>, <platform: windows-aarch64>, <platform: windows-x86>, <platform: windows-x86_64>, <platform: windows-armv7>, <platform: windows-thumb2>, <platform: windows-kernel-windows-aarch64>, <platform: windows-kernel-x86>, <platform: windows-kernel-x86_64>] >>> thumb2 = Platform["thumb2"] """ name = None type_file_path = None # path to platform types file type_include_dirs = [] # list of directories available to #include from type_file_path global_regs = [] # list of global registers. if empty, it populated with the arch global reg list global_reg_types = {} # opportunity for plugin to provide default types for the entry value of global registers _registered_platforms = [] def __init__(self, arch: Optional['architecture.Architecture'] = None, handle=None): if handle is None: if arch is None: raise ValueError("platform must have an associated architecture") assert self.__class__.name is not None, "Can not instantiate Platform directly, you probably want arch.standalone_platform" _arch = arch if len(self.global_regs) == 0: self.__dict__["global_regs"] = arch.global_regs self._cb = core.BNCustomPlatform() self._cb.context = 0 self._cb.init = self._cb.init.__class__(self._init) self._cb.viewInit = self._cb.viewInit.__class__(self._view_init) self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_regs) self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) self._cb.getGlobalRegisterType = self._cb.getGlobalRegisterType.__class__(self._get_global_reg_type) self._cb.adjustTypeParserInput = self._cb.adjustTypeParserInput.__class__(self._adjust_type_parser_input) self._cb.freeTypeParserInput = self._cb.freeTypeParserInput.__class__(self._free_type_parser_input) self._pending_reg_lists = {} self._pending_parser_input_lists = {} if self.__class__.type_file_path is None: _handle = core.BNCreateCustomPlatform(arch.handle, self.__class__.name, self._cb) assert _handle is not None else: dir_buf = (ctypes.c_char_p * len(self.__class__.type_include_dirs))() for (i, dir) in enumerate(self.__class__.type_include_dirs): dir_buf[i] = dir.encode('charmap') _handle = core.BNCreateCustomPlatformWithTypes( arch.handle, self.__class__.name, self._cb, self.__class__.type_file_path, dir_buf, len(self.__class__.type_include_dirs) ) assert _handle is not None self.__class__._registered_platforms.append(self) else: if type(self) is Platform: binaryninja.log_warn( ":py:func:`Platform(handle=...)` is deprecated, use :py:func:`CorePlatform._from_cache(handle=...)`" ) _handle = handle _arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(_handle)) count = ctypes.c_ulonglong() regs = core.BNGetPlatformGlobalRegisters(handle, count) result = [] for i in range(0, count.value): result.append(_arch.get_reg_name(regs[i])) core.BNFreeRegisterList(regs) self.__dict__["global_regs"] = result assert _handle is not None assert _arch is not None self.handle: ctypes.POINTER(core.BNPlatform) = _handle self._arch = _arch self._name = None def _init(self, ctxt): pass def _view_init(self, ctxt, view): try: view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view)) self.view_init(view) except: log_error(traceback.format_exc()) def _get_global_regs(self, ctxt, count): try: regs = self.global_regs count[0] = len(regs) reg_buf = (ctypes.c_uint * len(regs))() for i in range(0, len(regs)): reg_buf[i] = self.arch.regs[regs[i]].index result = ctypes.cast(reg_buf, ctypes.c_void_p) self._pending_reg_lists[result.value] = (result, reg_buf) return result.value except: log_error(traceback.format_exc()) count[0] = 0 return None def _free_register_list(self, ctxt, regs, size): try: buf = ctypes.cast(regs, ctypes.c_void_p) if buf.value not in self._pending_reg_lists: raise ValueError("freeing register list that wasn't allocated") del self._pending_reg_lists[buf.value] except: log_error(traceback.format_exc()) def _get_global_reg_type(self, ctxt, reg): try: reg_name = self.arch.get_reg_name(reg) if reg_name in self.global_reg_types: type_obj = self.global_reg_types[reg_name] handle = core.BNNewTypeReference(type_obj.handle) return ctypes.cast(handle, ctypes.c_void_p).value return None except: log_error(traceback.format_exc()) return None def _adjust_type_parser_input( self, ctxt, parser, arguments_in, arguments_len_in, source_file_names_in, source_file_values_in, source_files_len_in, arguments_out, arguments_len_out, source_file_names_out, source_file_values_out, source_files_len_out ): try: parser_py = typeparser.TypeParser(handle=parser) arguments = [] for i in range(arguments_len_in): arguments.append(core.pyNativeStr(arguments_in[i])) source_files = [] for i in range(source_files_len_in): source_files.append((core.pyNativeStr(source_file_names_in[i]), core.pyNativeStr(source_file_values_in[i]))) arguments, source_files = self.adjust_type_parser_input(parser_py, arguments, source_files) arguments_len_out[0] = len(arguments) arguments_buf = (ctypes.c_char_p * len(arguments))() for i, r in enumerate(arguments): arguments_buf[i] = core.cstr(r) arguments_ptr = ctypes.cast(arguments_buf, ctypes.c_void_p) arguments_out[0] = arguments_buf self._pending_parser_input_lists[arguments_ptr.value] = (arguments_ptr.value, arguments_buf) source_files_len_out[0] = len(source_files) source_file_names_buf = (ctypes.c_char_p * len(source_files))() source_file_values_buf = (ctypes.c_char_p * len(source_files))() for i, (name, value) in enumerate(source_files): source_file_names_buf[i] = core.cstr(name) source_file_values_buf[i] = core.cstr(value) source_file_names_ptr = ctypes.cast(source_file_names_buf, ctypes.c_void_p) source_file_names_out[0] = source_file_names_buf source_file_values_ptr = ctypes.cast(source_file_values_buf, ctypes.c_void_p) source_file_values_out[0] = source_file_values_buf self._pending_parser_input_lists[source_file_names_ptr.value] = (source_file_names_ptr.value, source_file_names_buf) self._pending_parser_input_lists[source_file_values_ptr.value] = (source_file_values_ptr.value, source_file_values_buf) except: arguments_out[0] = None arguments_len_out[0] = 0 source_file_names_out[0] = None source_file_values_out[0] = None source_files_len_out[0] = 0 traceback.print_exc() def _free_type_parser_input( self, ctxt, arguments, arguments_len, source_file_names, source_file_values, source_files_len ): try: buf = ctypes.cast(arguments, ctypes.c_void_p) if buf.value is not None: if buf.value not in self._pending_parser_input_lists: raise ValueError("freeing arguments list that wasn't allocated") del self._pending_parser_input_lists[buf.value] buf = ctypes.cast(source_file_names, ctypes.c_void_p) if buf.value is not None: if buf.value not in self._pending_parser_input_lists: raise ValueError("freeing source_file_names list that wasn't allocated") del self._pending_parser_input_lists[buf.value] buf = ctypes.cast(source_file_values, ctypes.c_void_p) if buf.value is not None: if buf.value not in self._pending_parser_input_lists: raise ValueError("freeing source_file_values list that wasn't allocated") del self._pending_parser_input_lists[buf.value] except: log_error(traceback.format_exc())
[docs] def adjust_type_parser_input( self, parser: 'typeparser.TypeParser', arguments: List[str], source_files: List[Tuple[str, str]] ) -> Tuple[List[str], List[Tuple[str, str]]]: """ Modify the arguments passed to the Type Parser with Platform-specific features. :param parser: Type Parser instance :param arguments: Default arguments passed to the parser :param source_files: Source file names and contents :return: A tuple of (modified arguments, modified source files) """ return arguments, source_files
def __del__(self): if core is not None: core.BNFreePlatform(self.handle) def __repr__(self): return f"<platform: {self.name}>" def __str__(self): return self.name def __eq__(self, other: 'Platform'): if not isinstance(other, self.__class__): return NotImplemented return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents) def __ne__(self, other: 'Platform'): if not isinstance(other, self.__class__): return NotImplemented return not (self == other) def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) @property def name(self) -> str: if self._name is None: self._name = core.BNGetPlatformName(self.handle) return self._name @classmethod @property def os_list(cls) -> List[str]: binaryninja._init_plugins() count = ctypes.c_ulonglong() platforms = core.BNGetPlatformOSList(count) assert platforms is not None, "core.BNGetPlatformOSList returned None" result:List[str] = [] for i in range(count.value): result.append(str(platforms[i])) core.BNFreePlatformOSList(platforms, count.value) return result
[docs] @classmethod def get_list(cls, os=None, arch=None): binaryninja._init_plugins() count = ctypes.c_ulonglong() if os is None: platforms = core.BNGetPlatformList(count) assert platforms is not None, "core.BNGetPlatformList returned None" elif arch is None: platforms = core.BNGetPlatformListByOS(os, count) assert platforms is not None, "core.BNGetPlatformListByOS returned None" else: platforms = core.BNGetPlatformListByArchitecture(arch.handle, count) assert platforms is not None, "core.BNGetPlatformListByArchitecture returned None" result = [] for i in range(0, count.value): result.append(CorePlatform._from_cache(core.BNNewPlatformReference(platforms[i]))) core.BNFreePlatformList(platforms, count.value) return result
@property def default_calling_convention(self): """ Default calling convention. :getter: returns a CallingConvention object for the default calling convention. :setter: sets the default calling convention :type: CallingConvention """ result = core.BNGetPlatformDefaultCallingConvention(self.handle) if result is None: return None return callingconvention.CallingConvention(handle=result) @default_calling_convention.setter def default_calling_convention(self, value): core.BNRegisterPlatformDefaultCallingConvention(self.handle, value.handle) @property def cdecl_calling_convention(self): """ CallingConvention object for the cdecl calling convention """ result = core.BNGetPlatformCdeclCallingConvention(self.handle) if result is None: return None return callingconvention.CallingConvention(handle=result) @cdecl_calling_convention.setter def cdecl_calling_convention(self, value): """ Sets the cdecl calling convention """ core.BNRegisterPlatformCdeclCallingConvention(self.handle, value.handle) @property def stdcall_calling_convention(self): """ CallingConvention object for the stdcall calling convention """ result = core.BNGetPlatformStdcallCallingConvention(self.handle) if result is None: return None return callingconvention.CallingConvention(handle=result) @stdcall_calling_convention.setter def stdcall_calling_convention(self, value): """ Sets the stdcall calling convention """ core.BNRegisterPlatformStdcallCallingConvention(self.handle, value.handle) @property def fastcall_calling_convention(self): """ CallingConvention object for the fastcall calling convention """ result = core.BNGetPlatformFastcallCallingConvention(self.handle) if result is None: return None return callingconvention.CallingConvention(handle=result) @fastcall_calling_convention.setter def fastcall_calling_convention(self, value): """ Sets the fastcall calling convention """ core.BNRegisterPlatformFastcallCallingConvention(self.handle, value.handle) @property def system_call_convention(self): """ CallingConvention object for the system call convention """ result = core.BNGetPlatformSystemCallConvention(self.handle) if result is None: return None return callingconvention.CallingConvention(handle=result) @system_call_convention.setter def system_call_convention(self, value): """ Sets the system call convention """ core.BNSetPlatformSystemCallConvention(self.handle, value.handle) @property def calling_conventions(self): """ List of platform CallingConvention objects (read-only) :getter: returns the list of supported CallingConvention objects :type: list(CallingConvention) """ count = ctypes.c_ulonglong() cc = core.BNGetPlatformCallingConventions(self.handle, count) assert cc is not None, "core.BNGetPlatformCallingConventions returned None" result = [] for i in range(0, count.value): result.append(callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i]))) core.BNFreeCallingConventionList(cc, count.value) return result
[docs] def get_global_register_type(self, reg: 'architecture.RegisterType'): reg = self.arch.get_reg_index(reg) type_obj = core.BNGetPlatformGlobalRegisterType(self.handle, reg) if type_obj is None: return None return types.Type.create(type_obj, platform=self)
[docs] def view_init(self, view): pass
#raise NotImplementedError @property def types(self): """List of platform-specific types (read-only)""" count = ctypes.c_ulonglong(0) type_list = core.BNGetPlatformTypes(self.handle, count) assert type_list is not None, "core.BNGetPlatformTypes returned None" result = {} 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.BNFreeTypeAndNameList(type_list, count.value) return result @property def variables(self): """List of platform-specific variable definitions (read-only)""" count = ctypes.c_ulonglong(0) type_list = core.BNGetPlatformVariables(self.handle, count) assert type_list is not None, "core.BNGetPlatformVariables returned None" result = {} 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.BNFreeTypeAndNameList(type_list, count.value) return result @property def functions(self): """List of platform-specific function definitions (read-only)""" count = ctypes.c_ulonglong(0) type_list = core.BNGetPlatformFunctions(self.handle, count) assert type_list is not None, "core.BNGetPlatformFunctions returned None" result = {} 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.BNFreeTypeAndNameList(type_list, count.value) return result @property def system_calls(self): """List of system calls for this platform (read-only)""" count = ctypes.c_ulonglong(0) call_list = core.BNGetPlatformSystemCalls(self.handle, count) assert call_list is not None, "core.BNGetPlatformSystemCalls returned None" result = {} for i in range(0, count.value): name = types.QualifiedName._from_core_struct(call_list[i].name) t = types.Type.create(core.BNNewTypeReference(call_list[i].type), platform=self) result[call_list[i].number] = (name, t) core.BNFreeSystemCallList(call_list, count.value) return result @property def type_libraries(self) -> List['typelibrary.TypeLibrary']: count = ctypes.c_ulonglong(0) libs = core.BNGetPlatformTypeLibraries(self.handle, count) assert libs is not None, "core.BNGetPlatformTypeLibraries returned None" result = [] for i in range(0, count.value): result.append(typelibrary.TypeLibrary(core.BNNewTypeLibraryReference(libs[i]))) core.BNFreeTypeLibraryList(libs, count.value) return result
[docs] def get_type_libraries_by_name(self, name) -> List['typelibrary.TypeLibrary']: count = ctypes.c_ulonglong(0) libs = core.BNGetPlatformTypeLibrariesByName(self.handle, name, count) assert libs is not None, "core.BNGetPlatformTypeLibrariesByName returned None" result = [] for i in range(0, count.value): result.append(typelibrary.TypeLibrary(core.BNNewTypeLibraryReference(libs[i]))) core.BNFreeTypeLibraryList(libs, count.value) return result
[docs] def register(self, os): """ ``register`` registers the platform for given OS name. :param str os: OS name to register :rtype: None """ core.BNRegisterPlatform(os, self.handle)
[docs] def register_calling_convention(self, cc): """ ``register_calling_convention`` register a new calling convention. :param CallingConvention cc: a CallingConvention object to register :rtype: None """ core.BNRegisterPlatformCallingConvention(self.handle, cc.handle)
[docs] def get_associated_platform_by_address(self, addr): new_addr = ctypes.c_ulonglong() new_addr.value = addr result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr) return CorePlatform._from_cache(result), new_addr.value
@property def type_container(self) -> 'typecontainer.TypeContainer': """ Type Container for all registered types in the Platform. :return: Platform types Type Container """ return typecontainer.TypeContainer(core.BNGetPlatformTypeContainer(self.handle))
[docs] def get_type_by_name(self, name): name = types.QualifiedName(name)._to_core_struct() obj = core.BNGetPlatformTypeByName(self.handle, name) if not obj: return None return types.Type.create(obj, platform=self)
[docs] def get_variable_by_name(self, name): name = types.QualifiedName(name)._to_core_struct() obj = core.BNGetPlatformVariableByName(self.handle, name) if not obj: return None return types.Type.create(obj, platform=self)
[docs] def get_function_by_name(self, name, exactMatch=False): name = types.QualifiedName(name)._to_core_struct() obj = core.BNGetPlatformFunctionByName(self.handle, name, exactMatch) if not obj: return None return types.Type.create(obj, platform=self)
[docs] def get_system_call_name(self, number): return core.BNGetPlatformSystemCallName(self.handle, number)
[docs] def get_system_call_type(self, number): obj = core.BNGetPlatformSystemCallType(self.handle, number) if not obj: return None return types.Type.create(obj, platform=self)
[docs] def generate_auto_platform_type_id(self, name): name = types.QualifiedName(name)._to_core_struct() return core.BNGenerateAutoPlatformTypeId(self.handle, name)
[docs] def generate_auto_platform_type_ref(self, type_class, name): type_id = self.generate_auto_platform_type_id(name) return types.NamedTypeReferenceBuilder.create(type_class, type_id, name)
[docs] def get_auto_platform_type_id_source(self): return core.BNGetAutoPlatformTypeIdSource(self.handle)
[docs] def parse_types_from_source( self, source, filename=None, include_dirs: Optional[List[str]] = None, auto_type_source=None ): """ ``parse_types_from_source`` parses the source string and any needed headers searching for them in the optional list of directories provided in ``include_dirs``. Note that this API does not allow the source to rely on existing types that only exist in a specific view. Use :py:meth:`BinaryView.parse_type_string` instead. :param str source: source string to be parsed :param str filename: optional source filename :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:`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') ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions:{'bar': <type: int32_t(int32_t x)>}}, '') >>> """ if filename is None: filename = "input" if not isinstance(source, str): raise AttributeError("Source must be a string") 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') parse = core.BNTypeParserResult() errors = ctypes.c_char_p() result = core.BNParseTypesFromSource( self.handle, source, filename, parse, errors, dir_buf, len(include_dirs), auto_type_source ) assert errors.value is not None, "core.BNParseTypesFromSource returned errors set to None" error_str = errors.value.decode("utf-8") core.free_string(errors) if not result: raise SyntaxError(error_str) type_dict: Dict[types.QualifiedName, types.Type] = {} variables: Dict[types.QualifiedName, types.Type] = {} functions: Dict[types.QualifiedName, types.Type] = {} for i in range(0, parse.typeCount): name = types.QualifiedName._from_core_struct(parse.types[i].name) type_dict[name] = types.Type.create(core.BNNewTypeReference(parse.types[i].type), platform=self) for i in range(0, parse.variableCount): name = types.QualifiedName._from_core_struct(parse.variables[i].name) variables[name] = types.Type.create(core.BNNewTypeReference(parse.variables[i].type), platform=self) for i in range(0, parse.functionCount): 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 typeparser.BasicTypeParserResult(type_dict, variables, functions)
[docs] def parse_types_from_source_file(self, filename, include_dirs: Optional[List[str]] = None, auto_type_source=None): """ ``parse_types_from_source_file`` parses the source file ``filename`` and any needed headers searching for them in the optional list of directories provided in ``include_dirs``. Note that this API does not allow the source to rely on existing types that only exist in a specific view. Use :py:meth:`BinaryView.parse_type_string` instead. :param str filename: filename of file to be parsed :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:`BasicTypeParserResult` (a SyntaxError is thrown on parse error) :rtype: BasicTypeParserResult :Example: >>> file = "/Users/binja/tmp.c" >>> open(file).read() 'int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n' >>> platform.parse_types_from_source_file(file) ({types: {'bas': <type: struct bas>}, variables: {'foo': <type: int32_t>}, functions: {'bar': <type: int32_t(int32_t x)>}}, '') >>> """ if not (isinstance(filename, str) and os.path.isfile(filename) and os.access(filename, os.R_OK)): raise AttributeError("File {} doesn't exist or isn't readable".format(filename)) 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') parse = core.BNTypeParserResult() errors = ctypes.c_char_p() result = core.BNParseTypesFromSourceFile( self.handle, filename, parse, errors, dir_buf, len(include_dirs), auto_type_source ) assert errors.value is not None, "core.BNParseTypesFromSourceFile returned errors set to None" error_str = errors.value.decode("utf-8") core.free_string(errors) if not result: raise SyntaxError(error_str) type_dict = {} variables = {} functions = {} for i in range(0, parse.typeCount): name = types.QualifiedName._from_core_struct(parse.types[i].name) type_dict[name] = types.Type.create(core.BNNewTypeReference(parse.types[i].type), platform=self) for i in range(0, parse.variableCount): name = types.QualifiedName._from_core_struct(parse.variables[i].name) variables[name] = types.Type.create(core.BNNewTypeReference(parse.variables[i].type), platform=self) for i in range(0, parse.functionCount): 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 typeparser.BasicTypeParserResult(type_dict, variables, functions)
@property def arch(self): return self._arch
_platform_cache = {}
[docs] class CorePlatform(Platform): def __init__(self, handle: core.BNPlatform): super(CorePlatform, self).__init__(handle=handle) if type(self) is CorePlatform: global _platform_cache _platform_cache[ctypes.addressof(handle.contents)] = self @classmethod def _from_cache(cls, handle) -> 'Platform': """ Look up a platform from a given BNPlatform handle :param handle: BNPlatform pointer :return: Platform instance responsible for this handle """ global _platform_cache return _platform_cache.get(ctypes.addressof(handle.contents)) or cls(handle)
[docs] def adjust_type_parser_input( self, parser: 'typeparser.TypeParser', arguments: List[str], source_files: List[Tuple[str, str]] ) -> Tuple[List[str], List[Tuple[str, str]]]: arguments_in = (ctypes.c_char_p * len(arguments))() for i, argument in enumerate(arguments): arguments_in[i] = core.cstr(argument) source_file_names_in = (ctypes.c_char_p * len(source_files))() source_file_names_out = (ctypes.c_char_p * len(source_files))() source_file_values_in = (ctypes.c_char_p * len(source_files))() source_file_values_out = (ctypes.c_char_p * len(source_files))() for i, (name, value) in enumerate(source_files): source_file_names_in[i] = core.cstr(name) source_file_values_in[i] = core.cstr(value) arguments_out = ctypes.POINTER(ctypes.c_char_p)() arguments_len_out = (ctypes.c_size_t)() source_file_names_out = ctypes.POINTER(ctypes.c_char_p)() source_file_values_out = ctypes.POINTER(ctypes.c_char_p)() source_files_len_out = (ctypes.c_size_t)() core.BNPlatformAdjustTypeParserInput( self.handle, parser.handle, arguments_in, len(arguments), source_file_names_in, source_file_values_in, len(source_files), arguments_out, arguments_len_out, source_file_names_out, source_file_values_out, source_files_len_out ) result_arguments = [] for i in range(arguments_len_out.value): result_arguments.append(core.pyNativeStr(arguments_out[i])) result_source_files = [] for i in range(source_files_len_out.value): result_source_files.append(( core.pyNativeStr(source_file_names_out[i]), core.pyNativeStr(source_file_values_out[i]), )) core.BNFreeStringList(arguments_out, arguments_len_out.value) core.BNFreeStringList(source_file_names_out, source_files_len_out.value) core.BNFreeStringList(source_file_values_out, source_files_len_out.value) return result_arguments, result_source_files