summaryrefslogtreecommitdiff
path: root/python/debuginfo.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/debuginfo.py')
-rw-r--r--python/debuginfo.py135
1 files changed, 64 insertions, 71 deletions
diff --git a/python/debuginfo.py b/python/debuginfo.py
index 15ac4efb..b3b80614 100644
--- a/python/debuginfo.py
+++ b/python/debuginfo.py
@@ -21,14 +21,15 @@
import ctypes
from typing import Optional, List, Iterator, Callable, Tuple
import traceback
+from dataclasses import dataclass
# Binary Ninja components
import binaryninja
-from binaryninja import _binaryninjacore as core
-from binaryninja import callingconvention
-from binaryninja import platform
-from binaryninja import types
-from binaryninja import log
+from . import _binaryninjacore as core
+from . import callingconvention
+from . import platform
+from . import types
+from . import log
_debug_info_parsers = {}
@@ -41,9 +42,12 @@ class _DebugInfoParserMetaClass(type):
binaryninja._init_plugins()
count = ctypes.c_ulonglong()
parsers = core.BNGetDebugInfoParsers(count)
+ assert parsers is not None, "core.BNGetDebugInfoParsers returned None"
result = []
for i in range(0, count.value):
- result.append(DebugInfoParser(core.BNNewDebugInfoParserReference(parsers[i])))
+ parser = core.BNNewDebugInfoParserReference(parsers[i])
+ assert parser is not None, "core.BNNewDebugInfoParserReference returned None"
+ result.append(DebugInfoParser(parser))
core.BNFreeDebugInfoParserList(parsers, count.value)
return result
@@ -52,9 +56,12 @@ class _DebugInfoParserMetaClass(type):
binaryninja._init_plugins()
count = ctypes.c_ulonglong()
parsers = core.BNGetDebugInfoParsers(count)
+ assert parsers is not None, "core.BNGetDebugInfoParsers returned None"
try:
for i in range(0, count.value):
- yield DebugInfoParser(core.BNNewDebugInfoParserReference(parsers[i]))
+ parser = core.BNNewDebugInfoParserReference(parsers[i])
+ assert parser is not None, "core.BNNewDebugInfoParserReference returned None"
+ yield DebugInfoParser(parser)
finally:
core.BNFreeDebugInfoParserList(parsers, count.value)
@@ -64,7 +71,9 @@ class _DebugInfoParserMetaClass(type):
parser = core.BNGetDebugInfoParserByName(str(value))
if parser is None:
raise KeyError(f"'{str(value)}' is not a valid debug-info parser")
- return DebugInfoParser(core.BNNewDebugInfoParserReference(parser))
+ parser_ref = core.BNNewDebugInfoParserReference(parser)
+ assert parser_ref is not None, "core.BNNewDebugInfoParserReference returned None"
+ return DebugInfoParser(parser_ref)
@staticmethod
def get_parsers_for_view(view: binaryninja.binaryview.BinaryView) -> List["DebugInfoParser"]:
@@ -73,10 +82,15 @@ class _DebugInfoParserMetaClass(type):
count = ctypes.c_ulonglong()
parsers = core.BNGetDebugInfoParsersForView(view.handle, count)
+ assert parsers is not None, "core.BNGetDebugInfoParsersForView returned None"
result = []
- for i in range(0, count.value):
- result.append(DebugInfoParser(core.BNNewDebugInfoParserReference(parsers[i])))
- core.BNFreeDebugInfoParserList(parsers, count.value)
+ try:
+ for i in range(0, count.value):
+ parser_ref = core.BNNewDebugInfoParserReference(parsers[i])
+ assert parser_ref is not None, "core.BNNewDebugInfoParserReference returned None"
+ result.append(DebugInfoParser(parser_ref))
+ finally:
+ core.BNFreeDebugInfoParserList(parsers, count.value)
return result
@staticmethod
@@ -87,13 +101,16 @@ class _DebugInfoParserMetaClass(type):
return callback(view_obj)
except:
log.log_error(traceback.format_exc())
+ return False
@staticmethod
def _parse_info(debug_info: core.BNDebugInfo, view: core.BNBinaryView, callback: Callable[["DebugInfo", binaryninja.binaryview.BinaryView], None]) -> None:
try:
file_metadata = binaryninja.filemetadata.FileMetadata(handle = core.BNGetFileForView(view))
view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view))
- callback(DebugInfo(core.BNNewDebugInfoReference(debug_info)), view_obj)
+ parser_ref = core.BNNewDebugInfoReference(debug_info)
+ assert parser_ref is not None, "core.BNNewDebugInfoReference returned None"
+ callback(DebugInfo(parser_ref), view_obj)
except:
log.log_error(traceback.format_exc())
@@ -108,8 +125,11 @@ class _DebugInfoParserMetaClass(type):
# Don't let our callbacks get garbage collected
global _debug_info_parsers
_debug_info_parsers[len(_debug_info_parsers)] = (is_valid_cb, parse_info_cb)
-
- return DebugInfoParser(core.BNNewDebugInfoParserReference(core.BNRegisterDebugInfoParser(name, is_valid_cb, parse_info_cb, None)))
+ parser = core.BNRegisterDebugInfoParser(name, is_valid_cb, parse_info_cb, None)
+ assert parser is not None, "core.BNRegisterDebugInfoParser is not None"
+ parser_ref = core.BNNewDebugInfoParserReference(parser)
+ assert parser_ref is not None, "core.BNNewDebugInfoParserReference returned None"
+ return DebugInfoParser(parser_ref)
class DebugInfoParser(object, metaclass=_DebugInfoParserMetaClass):
@@ -189,11 +209,18 @@ class DebugInfoParser(object, metaclass=_DebugInfoParserMetaClass):
def parse_debug_info(self, view: binaryninja.binaryview.BinaryView, debug_info: Optional["DebugInfo"] = None) -> "DebugInfo":
"""Returns a ``DebugInfo`` object populated with debug info by this debug-info parser. Only provide a ``DebugInfo`` object if you wish to append to the existing debug info"""
if isinstance(debug_info, DebugInfo):
- return DebugInfo(core.BNNewDebugInfoReference(core.BNParseDebugInfo(self.handle, view.handle, debug_info.handle)))
+ parser = core.BNParseDebugInfo(self.handle, view.handle, debug_info.handle)
+ assert parser is not None, "core.BNParseDebugInfo returned None"
+ parser_ref = core.BNNewDebugInfoReference(parser)
+ assert parser_ref is not None, "core.BNNewDebugInfoReference returned None"
+ return DebugInfo(parser_ref)
else:
- return DebugInfo(core.BNParseDebugInfo(self.handle, view.handle, None))
+ parser = core.BNParseDebugInfo(self.handle, view.handle, None)
+ assert parser is not None, "core.BNParseDebugInfo returned None"
+ return DebugInfo(parser)
+@dataclass(frozen=True)
class DebugFunctionInfo(object):
"""
``DebugFunctionInfo`` collates ground-truth function-external attributes for use in BinaryNinja's internal analysis.
@@ -202,64 +229,27 @@ class DebugFunctionInfo(object):
Functions will not be created if an address is not provided, but will be able to be queried from debug info for later user analysis.
"""
- def __init__(self, address: Optional[int] = 0, short_name: Optional[str] = None, full_name: Optional[str] = None, raw_name: Optional[str] = None, return_type: Optional[types.Type] = None, parameters: Optional[List[Tuple[str, types.Type]]] = None, variable_parameters: Optional[bool] = False, calling_convention: Optional[callingconvention.CallingConvention] = None, platform: Optional[platform.Platform] = None) -> None:
- self._short_name = short_name
- self._full_name = full_name
- self._raw_name = raw_name
- self._address = address
- self._return_type = return_type
- self._parameters = parameters
- self._variable_parameters = variable_parameters
- self._calling_convention = calling_convention
- self._platform = platform
+ short_name:Optional[str]
+ full_name:Optional[str]
+ raw_name:Optional[str]
+ address:Optional[int]
+ return_type:Optional[types.Type]
+ parameters:Optional[List[Tuple[str, types.Type]]]
+ variable_parameters:Optional[bool]
+ calling_convention:Optional[callingconvention.CallingConvention]
+ platform:Optional[platform.Platform]
def __repr__(self) -> str:
- suffix = f"@{hex(self._address)}>" if self._address != 0 else ">"
- if self._short_name is not None:
- return f"<debug-info function: {self._short_name}{suffix}"
- elif self._full_name is not None:
- return f"<debug-info function: {self._full_name}{suffix}"
- elif self._raw_name is not None:
- return f"<debug-info function: {self._raw_name}{suffix}"
+ suffix = f"@{self.address:#x}>" if self.address != 0 else ">"
+ if self.short_name is not None:
+ return f"<debug-info function: {self.short_name}{suffix}"
+ elif self.full_name is not None:
+ return f"<debug-info function: {self.full_name}{suffix}"
+ elif self.raw_name is not None:
+ return f"<debug-info function: {self.raw_name}{suffix}"
else:
return f"<debug-info function{suffix}"
- @property
- def short_name(self) -> Optional[str]:
- return self._short_name
-
- @property
- def full_name(self) -> Optional[str]:
- return self._full_name
-
- @property
- def raw_name(self) -> Optional[str]:
- return self._raw_name
-
- @property
- def address(self) -> Optional[int]:
- return self._address
-
- @property
- def return_type(self) -> Optional[int]:
- return self._return_type
-
- @property
- def parameters(self) -> Optional[List[Tuple[str, types.Type]]]:
- return self._parameters
-
- @property
- def variable_parameters(self) -> Optional[bool]:
- return self._variable_parameters
-
- @property
- def calling_convention(self) -> Optional[callingconvention.CallingConvention]:
- return self._calling_convention
-
- @property
- def platform(self) -> Optional[platform.Platform]:
- return self._platform
-
class DebugInfo(object):
"""
@@ -287,6 +277,7 @@ class DebugInfo(object):
"""Returns a generator of all types provided by a named DebugInfoParser"""
count = ctypes.c_ulonglong(0)
name_and_types = core.BNGetDebugTypes(self.handle, name, count)
+ assert name_and_types is not None, "core.BNGetDebugTypes returned None"
try:
for i in range(0, count.value):
yield (name_and_types[i].name, types.Type(core.BNNewTypeReference(name_and_types[i].type)))
@@ -302,6 +293,7 @@ class DebugInfo(object):
"""Returns a generator of all functions provided by a named DebugInfoParser"""
count = ctypes.c_ulonglong(0)
functions = core.BNGetDebugFunctions(self.handle, name, count)
+ assert functions is not None, "core.BNGetDebugFunctions returned None"
try:
for i in range(0, count.value):
@@ -347,6 +339,7 @@ class DebugInfo(object):
"""Returns a generator of all data variables provided by a named DebugInfoParser"""
count = ctypes.c_ulonglong(0)
data_variables = core.BNGetDebugDataVariables(self.handle, name, count)
+ assert data_variables is not None, "core.BNGetDebugDataVariables returned None"
try:
for i in range(0, count.value):
yield binaryninja.binaryview.DataVariableAndName(
@@ -413,8 +406,8 @@ class DebugInfo(object):
func_info.parameterTypes = None
func_info.parameterCount = parameter_count
else:
- func_info.parameterNames = (ctypes.c_char_p * parameter_count)(*map(lambda pair: binaryninja.cstr(pair[0]), new_func.parameters))
- func_info.parameterTypes = (ctypes.POINTER(core.BNType) * parameter_count)(*map(lambda pair: pair[1].handle, new_func.parameters))
+ func_info.parameterNames = (ctypes.c_char_p * parameter_count)(*map(lambda pair: binaryninja.cstr(pair[0]), new_func.parameters)) # type: ignore
+ func_info.parameterTypes = (ctypes.POINTER(core.BNType) * parameter_count)(*map(lambda pair: pair[1].handle, new_func.parameters)) # type: ignore
func_info.parameterCount = parameter_count
return core.BNAddDebugFunction(self.handle, func_info)