summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2017-03-05 13:12:01 -0500
committerPeter LaFosse <peter@vector35.com>2017-03-05 13:12:01 -0500
commitcf5997848b8819725315bd2c8dd8a04c70da3b63 (patch)
tree24d9360e3ccfaee361aca4d345072c142c386a41 /python
parenta0132eed82d28d4408a2475847e1804a157b3dc1 (diff)
parent27f1271083efb09efc6405f91be893ab38dad9a0 (diff)
Merginging with dev
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py28
-rw-r--r--python/architecture.py68
-rw-r--r--python/basicblock.py137
-rw-r--r--python/binaryview.py249
-rw-r--r--python/callingconvention.py10
-rw-r--r--python/demangle.py4
-rwxr-xr-xpython/examples/export_svg.py9
-rw-r--r--python/examples/version_switcher.py34
-rw-r--r--python/filemetadata.py10
-rw-r--r--python/function.py82
-rw-r--r--python/generator.cpp56
-rw-r--r--python/lowlevelil.py14
-rw-r--r--python/platform.py101
-rw-r--r--python/plugin.py20
-rw-r--r--python/transform.py10
-rw-r--r--python/types.py348
-rw-r--r--python/update.py24
17 files changed, 1035 insertions, 169 deletions
diff --git a/python/__init__.py b/python/__init__.py
index 5df7c7f1..f028bc5b 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -49,9 +49,25 @@ from .pluginmanager import *
def shutdown():
+ """
+ ``shutdown`` cleanly shuts down the core, stopping all workers and closing all log files.
+ """
core.BNShutdown()
+def get_unique_identifier():
+ return core.BNGetUniqueIdentifierString()
+
+
+def get_install_directory():
+ """
+ ``get_install_directory`` returns a string pointing to the installed binary currently running
+
+ .warning:: ONLY for use within the Binary Ninja UI, behavior is undefined and unreliable if run headlessly
+ """
+ return core.BNGetInstallDirectory()
+
+
class _DestructionCallbackHandler(object):
def __init__(self):
self._cb = core.BNObjectDestructionCallbacks()
@@ -77,4 +93,16 @@ bundled_plugin_path = core.BNGetBundledPluginDirectory()
user_plugin_path = core.BNGetUserPluginDirectory()
core_version = core.BNGetVersionString()
+'''Core version'''
+
core_build_id = core.BNGetBuildId()
+'''Build ID'''
+
+core_product = core.BNGetProduct()
+'''Product string from the license file'''
+
+core_product_type = core.BNGetProductType()
+'''Product type from the license file'''
+
+core_license_count = core.BNGetLicenseCount()
+'''License count from the license file'''
diff --git a/python/architecture.py b/python/architecture.py
index f1440ca3..39e5e72d 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -333,6 +333,16 @@ class Architecture(object):
self._pending_reg_lists = {}
self._pending_token_lists = {}
+ def __eq__(self, value):
+ if not isinstance(value, Architecture):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Architecture):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def full_width_regs(self):
"""List of full width register strings (read-only)"""
@@ -364,7 +374,7 @@ class Architecture(object):
def __setattr__(self, name, value):
if ((name == "name") or (name == "endianness") or (name == "address_size") or
- (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")):
+ (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length")):
raise AttributeError("attribute '%s' is read only" % name)
else:
try:
@@ -467,6 +477,8 @@ class Architecture(object):
token_buf[i].value = tokens[i].value
token_buf[i].size = tokens[i].size
token_buf[i].operand = tokens[i].operand
+ token_buf[i].context = tokens[i].context
+ token_buf[i].address = tokens[i].address
result[0] = token_buf
ptr = ctypes.cast(token_buf, ctypes.c_void_p)
self._pending_token_lists[ptr.value] = (ptr.value, token_buf)
@@ -1148,7 +1160,9 @@ class Architecture(object):
value = tokens[i].value
size = tokens[i].size
operand = tokens[i].operand
- result.append(function.InstructionTextToken(token_type, text, value, size, operand))
+ context = tokens[i].context
+ address = tokens[i].address
+ result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
core.BNFreeInstructionText(tokens, count.value)
return result, length.value
@@ -1160,8 +1174,8 @@ class Architecture(object):
def get_instruction_low_level_il(self, data, addr, il):
"""
- ``get_instruction_low_level_il`` appends LowLevelILExpr objects for the instruction at the given virtual
- address ``addr`` with data ``data``.
+ ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given
+ virtual address ``addr`` with data ``data``.
:param str data: max_instruction_length bytes from the binary at virtual address ``addr``
:param int addr: virtual address of bytes in ``data``
@@ -1581,7 +1595,7 @@ class Architecture(object):
"""
core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value)
- def parse_types_from_source(self, source, filename=None, include_dirs=[]):
+ def parse_types_from_source(self, source, filename=None, include_dirs=[], 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``.
@@ -1589,8 +1603,9 @@ class Architecture(object):
:param str source: source string to be parsed
:param str filename: optional source filename
:param list(str) include_dirs: optional list of string filename include directories
- :return: a tuple of py:class:`TypeParserResult` and error string
- :rtype: tuple(TypeParserResult,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
:Example:
>>> arch.parse_types_from_source('int foo;\\nint bar(int x);\\nstruct bas{int x,y;};\\n')
@@ -1606,32 +1621,37 @@ class Architecture(object):
dir_buf[i] = str(include_dirs[i])
parse = core.BNTypeParserResult()
errors = ctypes.c_char_p()
- result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, len(include_dirs))
+ result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf,
+ len(include_dirs), auto_type_source)
error_str = errors.value
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
if not result:
- return (None, error_str)
+ raise SyntaxError(error_str)
type_dict = {}
variables = {}
functions = {}
for i in xrange(0, parse.typeCount):
- types[parse.types[i].name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
+ name = types.QualifiedName._from_core_struct(parse.types[i].name)
+ type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
for i in xrange(0, parse.variableCount):
- variables[parse.variables[i].name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
+ name = types.QualifiedName._from_core_struct(parse.variables[i].name)
+ variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
for i in xrange(0, parse.functionCount):
- functions[parse.functions[i].name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
+ name = types.QualifiedName._from_core_struct(parse.functions[i].name)
+ functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
core.BNFreeTypeParserResult(parse)
- return (types.TypeParserResult(type_dict, variables, functions), error_str)
+ return types.TypeParserResult(type_dict, variables, functions)
- def parse_types_from_source_file(self, filename, include_dirs=[]):
+ def parse_types_from_source_file(self, filename, include_dirs=[], 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``.
:param str filename: filename of file to be parsed
:param list(str) include_dirs: optional list of string filename include directories
- :return: a tuple of py:class:`TypeParserResult` and error string
- :rtype: tuple(TypeParserResult, 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
:Example:
>>> file = "/Users/binja/tmp.c"
@@ -1647,22 +1667,26 @@ class Architecture(object):
dir_buf[i] = str(include_dirs[i])
parse = core.BNTypeParserResult()
errors = ctypes.c_char_p()
- result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, len(include_dirs))
+ result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf,
+ len(include_dirs), auto_type_source)
error_str = errors.value
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
if not result:
- return (None, error_str)
+ raise SyntaxError(error_str)
type_dict = {}
variables = {}
functions = {}
for i in xrange(0, parse.typeCount):
- type_dict[parse.types[i].name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
+ name = types.QualifiedName._from_core_struct(parse.types[i].name)
+ type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type))
for i in xrange(0, parse.variableCount):
- variables[parse.variables[i].name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
+ name = types.QualifiedName._from_core_struct(parse.variables[i].name)
+ variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type))
for i in xrange(0, parse.functionCount):
- functions[parse.functions[i].name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
+ name = types.QualifiedName._from_core_struct(parse.functions[i].name)
+ functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type))
core.BNFreeTypeParserResult(parse)
- return (types.TypeParserResult(type_dict, variables, functions), error_str)
+ return types.TypeParserResult(type_dict, variables, functions)
def register_calling_convention(self, cc):
"""
diff --git a/python/basicblock.py b/python/basicblock.py
index ae9889fc..9f256aa7 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -29,19 +29,23 @@ import function
class BasicBlockEdge(object):
- def __init__(self, branch_type, target, arch):
+ def __init__(self, branch_type, source, target):
self.type = branch_type
- if self.type != BranchType.UnresolvedBranch:
- self.target = target
- self.arch = arch
+ self.source = source
+ self.target = target
def __repr__(self):
if self.type == BranchType.UnresolvedBranch:
return "<%s>" % BranchType(self.type).name
- elif self.arch:
- return "<%s: %s@%#x>" % (self.type, self.arch.name, self.target)
+ elif self.target.arch:
+ return "<%s: %s@%#x>" % (BranchType(self.type).name, self.target.arch.name, self.target.start)
else:
- return "<%s: %#x>" % (self.type, self.target)
+ return "<%s: %#x>" % (BranchType(self.type).name, self.target.start)
+
+ @property
+ def back_edge(self):
+ """Whether the edge is a back edge (end of a loop)"""
+ return self.target in self.source.dominators
class BasicBlock(object):
@@ -52,6 +56,16 @@ class BasicBlock(object):
def __del__(self):
core.BNFreeBasicBlock(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, BasicBlock):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BasicBlock):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def function(self):
"""Basic block function (read-only)"""
@@ -84,20 +98,40 @@ class BasicBlock(object):
return core.BNGetBasicBlockLength(self.handle)
@property
+ def index(self):
+ """Basic block index in list of blocks for the function (read-only)"""
+ return core.BNGetBasicBlockIndex(self.handle)
+
+ @property
def outgoing_edges(self):
"""List of basic block outgoing edges (read-only)"""
count = ctypes.c_ulonglong(0)
edges = core.BNGetBasicBlockOutgoingEdges(self.handle, count)
result = []
for i in xrange(0, count.value):
- branch_type = edges[i].type
- target = edges[i].target
- if edges[i].arch:
- arch = architecture.Architecture(edges[i].arch)
+ branch_type = BranchType(edges[i].type)
+ if edges[i].target:
+ target = BasicBlock(self.view, core.BNNewBasicBlockReference(edges[i].target))
else:
- arch = None
- result.append(BasicBlockEdge(branch_type, target, arch))
- core.BNFreeBasicBlockOutgoingEdgeList(edges)
+ target = None
+ result.append(BasicBlockEdge(branch_type, self, target))
+ core.BNFreeBasicBlockEdgeList(edges, count.value)
+ return result
+
+ @property
+ def incoming_edges(self):
+ """List of basic block incoming edges (read-only)"""
+ count = ctypes.c_ulonglong(0)
+ edges = core.BNGetBasicBlockIncomingEdges(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ branch_type = BranchType(edges[i].type)
+ if edges[i].target:
+ target = BasicBlock(self.view, core.BNNewBasicBlockReference(edges[i].target))
+ else:
+ target = None
+ result.append(BasicBlockEdge(branch_type, self, target))
+ core.BNFreeBasicBlockEdgeList(edges, count.value)
return result
@property
@@ -106,6 +140,58 @@ class BasicBlock(object):
return core.BNBasicBlockHasUndeterminedOutgoingEdges(self.handle)
@property
+ def dominators(self):
+ """List of dominators for this basic block (read-only)"""
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetBasicBlockDominators(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self.view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+
+ @property
+ def strict_dominators(self):
+ """List of strict dominators for this basic block (read-only)"""
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetBasicBlockStrictDominators(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self.view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+
+ @property
+ def immediate_dominator(self):
+ """Immediate dominator of this basic block (read-only)"""
+ result = core.BNGetBasicBlockImmediateDominator(self.handle)
+ if not result:
+ return None
+ return BasicBlock(self.view, result)
+
+ @property
+ def dominator_tree_children(self):
+ """List of child blocks in the dominator tree for this basic block (read-only)"""
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetBasicBlockDominatorTreeChildren(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self.view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+
+ @property
+ def dominance_frontier(self):
+ """Dominance frontier for this basic block (read-only)"""
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetBasicBlockDominanceFrontier(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(self.view, core.BNNewBasicBlockReference(blocks[i])))
+ core.BNFreeBasicBlockList(blocks, count.value)
+ return result
+
+ @property
def annotations(self):
"""List of automatic annotations for the start of this block (read-only)"""
return self.function.get_block_annotations(self.arch, self.start)
@@ -144,6 +230,21 @@ class BasicBlock(object):
def highlight(self, value):
self.set_user_highlight(value)
+ @classmethod
+ def get_iterated_dominance_frontier(self, blocks):
+ if len(blocks) == 0:
+ return []
+ block_set = (ctypes.POINTER(core.BNBasicBlock) * len(blocks))()
+ for i in xrange(len(blocks)):
+ block_set[i] = blocks[i].handle
+ count = ctypes.c_ulonglong()
+ out_blocks = core.BNGetBasicBlockIteratedDominanceFrontier(block_set, len(blocks), count)
+ result = []
+ for i in xrange(0, count.value):
+ result.append(BasicBlock(blocks[0].view, core.BNNewBasicBlockReference(out_blocks[i])))
+ core.BNFreeBasicBlockList(out_blocks, count.value)
+ return result
+
def __setattr__(self, name, value):
try:
object.__setattr__(self, name, value)
@@ -200,7 +301,9 @@ class BasicBlock(object):
value = lines[i].tokens[j].value
size = lines[i].tokens[j].size
operand = lines[i].tokens[j].operand
- tokens.append(function.InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].tokens[j].context
+ address = lines[i].tokens[j].address
+ tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
result.append(function.DisassemblyTextLine(addr, tokens))
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
@@ -215,6 +318,8 @@ class BasicBlock(object):
"""
if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
+ if isinstance(color, HighlightStandardColor):
+ color = highlight.HighlightColor(color)
core.BNSetAutoBasicBlockHighlight(self.handle, color._get_core_struct())
def set_user_highlight(self, color):
@@ -229,4 +334,6 @@ class BasicBlock(object):
"""
if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
+ if isinstance(color, HighlightStandardColor):
+ color = highlight.HighlightColor(color)
core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct())
diff --git a/python/binaryview.py b/python/binaryview.py
index af7faa32..dd37be69 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -78,6 +78,12 @@ class BinaryDataNotification(object):
def string_removed(self, view, string_type, offset, length):
pass
+ def type_defined(self, view, name, type):
+ pass
+
+ def type_undefined(self, view, name, type):
+ pass
+
class StringReference(object):
def __init__(self, string_type, start, length):
@@ -157,6 +163,8 @@ class BinaryDataNotificationCallbacks(object):
self._cb.dataVariableUpdated = self._cb.dataVariableUpdated.__class__(self._data_var_updated)
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
+ self._cb.typeUndefined = self._cb.typeUndefined.__class__(self._type_undefined)
def _register(self):
core.BNRegisterDataNotification(self.view.handle, self._cb)
@@ -239,6 +247,20 @@ class BinaryDataNotificationCallbacks(object):
except:
log.log_error(traceback.format_exc())
+ def _type_defined(self, ctxt, name, type_obj):
+ try:
+ qualified_name = types.QualifiedName._from_core_struct(name[0])
+ self.notify.type_defined(self.view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _type_undefined(self, ctxt, name, type_obj):
+ try:
+ qualified_name = types.QualifiedName._from_core_struct(name[0])
+ self.notify.type_undefined(self.view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ except:
+ log.log_error(traceback.format_exc())
+
class _BinaryViewTypeMetaclass(type):
@property
@@ -277,6 +299,16 @@ class BinaryViewType(object):
def __init__(self, handle):
self.handle = core.handle_of_type(handle, core.BNBinaryViewType)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryViewType):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryViewType):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def name(self):
"""BinaryView name (read-only)"""
@@ -326,7 +358,11 @@ class BinaryViewType(object):
return None
for available in view.available_view_types:
if available.name != "Raw":
- bv = cls[available.name].open(filename)
+ if filename.endswith(".bndb"):
+ bv = view.get_view_of_type(available.name)
+ else:
+ bv = cls[available.name].open(filename)
+
if update_analysis:
bv.update_analysis_and_wait()
return bv
@@ -521,6 +557,16 @@ class BinaryView(object):
self.notifications = {}
self.next_address = None # Do NOT try to access view before init() is called, use placeholder
+ def __eq__(self, value):
+ if not isinstance(value, BinaryView):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryView):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@classmethod
def register(cls):
startup._init_plugins()
@@ -754,7 +800,7 @@ class BinaryView(object):
syms = core.BNGetSymbols(self.handle, count)
result = {}
for i in xrange(0, count.value):
- sym = function.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i]))
+ sym = types.Symbol(None, None, None, handle=core.BNNewSymbolReference(syms[i]))
result[sym.raw_name] = sym
core.BNFreeSymbolList(syms, count.value)
return result
@@ -821,7 +867,8 @@ class BinaryView(object):
type_list = core.BNGetAnalysisTypeList(self.handle, count)
result = {}
for i in xrange(0, count.value):
- result[type_list[i].name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ name = types.QualifiedName._from_core_struct(type_list[i].name)
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
core.BNFreeTypeList(type_list, count.value)
return result
@@ -1863,7 +1910,7 @@ class BinaryView(object):
var = core.BNDataVariable()
if not core.BNGetDataVariableAtAddress(self.handle, addr, var):
return None
- return DataVariable(var.address, type.Type(var.type), var.autoDiscovered)
+ return DataVariable(var.address, types.Type(var.type), var.autoDiscovered)
def get_function_at(self, addr, plat=None):
"""
@@ -1929,7 +1976,7 @@ class BinaryView(object):
def get_basic_blocks_starting_at(self, addr):
"""
- ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address.
+ ``get_basic_blocks_starting_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address.
:param int addr: virtual address of BasicBlock desired
:return: a list of :py:Class:`BasicBlock` objects
@@ -2727,7 +2774,9 @@ class BinaryView(object):
value = lines[i].contents.tokens[j].value
size = lines[i].contents.tokens[j].size
operand = lines[i].contents.tokens[j].operand
- tokens.append(function.InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].contents.tokens[j].context
+ address = lines[i].contents.tokens[j].address
+ tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
contents = function.DisassemblyTextLine(addr, tokens)
result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents))
@@ -2827,51 +2876,117 @@ class BinaryView(object):
``parse_type_string`` converts `C-style` string into a :py:Class:`Type`.
:param str text: `C-style` string of type to create
- :return: A tuple of a :py:Class:`Type` and string type name
- :rtype: tuple(Type, str)
+ :return: A tuple of a :py:Class:`Type` and type name
+ :rtype: tuple(Type, QualifiedName)
:Example:
>>> bv.parse_type_string("int foo")
(<type: int32_t>, 'foo')
>>>
"""
- result = core.BNNameAndType()
+ result = core.BNQualifiedNameAndType()
errors = ctypes.c_char_p()
if not core.BNParseTypeString(self.handle, text, result, errors):
error_str = errors.value
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise SyntaxError(error_str)
type_obj = types.Type(core.BNNewTypeReference(result.type))
- name = result.name
- core.BNFreeNameAndType(result)
+ name = types.QualifiedName._from_core_struct(result.name)
+ core.BNFreeQualifiedNameAndType(result)
return type_obj, name
def get_type_by_name(self, name):
"""
``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name``
- :param str name: Type name to lookup
+ :param QualifiedName name: Type name to lookup
:return: A :py:Class:`Type` or None if the type does not exist
:rtype: Type or None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> bv.define_user_type(name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
obj = core.BNGetAnalysisTypeByName(self.handle, name)
if not obj:
return None
return types.Type(obj)
+ def get_type_by_id(self, id):
+ """
+ ``get_type_by_id`` returns the defined type whose unique identifier corresponds with the provided ``id``
+
+ :param str id: Unique identifier to lookup
+ :return: A :py:Class:`Type` or None if the type does not exist
+ :rtype: Type or None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
+ >>> bv.get_type_by_id(type_id)
+ <type: int32_t>
+ >>>
+ """
+ obj = core.BNGetAnalysisTypeById(self.handle, id)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def get_type_name_by_id(self, id):
+ """
+ ``get_type_name_by_id`` returns the defined type name whose unique identifier corresponds with the provided ``id``
+
+ :param str id: Unique identifier to lookup
+ :return: A QualifiedName or None if the type does not exist
+ :rtype: QualifiedName or None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
+ 'foo'
+ >>> bv.get_type_name_by_id(type_id)
+ 'foo'
+ >>>
+ """
+ name = core.BNGetAnalysisTypeNameById(self.handle, id)
+ result = types.QualifiedName._from_core_struct(name)
+ core.BNFreeQualifiedName(name)
+ if len(result) == 0:
+ return None
+ return result
+
+ def get_type_id(self, name):
+ """
+ ``get_type_id`` returns the unique indentifier of the defined type whose name corresponds with the
+ provided ``name``
+
+ :param QualifiedName name: Type name to lookup
+ :return: The unique identifier of the type
+ :rtype: str
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> registered_name = bv.define_type(type_id, name, type)
+ >>> bv.get_type_id(registered_name) == type_id
+ True
+ >>>
+ """
+ name = types.QualifiedName(name)._get_core_struct()
+ return core.BNGetAnalysisTypeId(self.handle, name)
+
def is_type_auto_defined(self, name):
"""
``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name
is considered an *auto* type.
- :param str name: Name of type to query
+ :param QualifiedName name: Name of type to query
:return: True if the type is not a *user* type. False if the type is a *user* type.
:Example:
>>> bv.is_type_auto_defined("foo")
@@ -2881,31 +2996,38 @@ class BinaryView(object):
False
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
return core.BNIsAnalysisTypeAutoDefined(self.handle, name)
- def define_type(self, name, type_obj):
+ def define_type(self, type_id, default_name, type_obj):
"""
``define_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of types for
- the current :py:Class:`BinaryView`.
+ the current :py:Class:`BinaryView`. This method should only be used for automatically generated types.
- :param str name: Name of the type to be registered
+ :param str type_id: Unique identifier for the automatically generated type
+ :param QualifiedName default_name: Name of the type to be registered
:param Type type_obj: Type object to be registered
- :rtype: None
+ :return: Registered name of the type. May not be the same as the requested name if the user has renamed types.
+ :rtype: QualifiedName
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
- >>> bv.get_type_by_name(name)
+ >>> registered_name = bv.define_type(Type.generate_auto_type_id("source", name), name, type)
+ >>> bv.get_type_by_name(registered_name)
<type: int32_t>
"""
- core.BNDefineAnalysisType(self.handle, name, type_obj.handle)
+ name = types.QualifiedName(default_name)._get_core_struct()
+ reg_name = core.BNDefineAnalysisType(self.handle, type_id, name, type_obj.handle)
+ result = types.QualifiedName._from_core_struct(reg_name)
+ core.BNFreeQualifiedName(reg_name)
+ return result
def define_user_type(self, name, type_obj):
"""
``define_user_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of user
types for the current :py:Class:`BinaryView`.
- :param str name: Name of the user type to be registered
+ :param QualifiedName name: Name of the user type to be registered
:param Type type_obj: Type object to be registered
:rtype: None
:Example:
@@ -2915,45 +3037,86 @@ class BinaryView(object):
>>> bv.get_type_by_name(name)
<type: int32_t>
"""
+ name = types.QualifiedName(name)._get_core_struct()
core.BNDefineUserAnalysisType(self.handle, name, type_obj.handle)
- def undefine_type(self, name):
+ def undefine_type(self, type_id):
"""
``undefine_type`` removes a :py:Class:`Type` from the global list of types for the current :py:Class:`BinaryView`
- :param str name: Name of type to be undefined
+ :param str type_id: Unique identifier of type to be undefined
:rtype: None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
- >>> bv.undefine_type(name)
+ >>> bv.undefine_type(type_id)
>>> bv.get_type_by_name(name)
>>>
"""
- core.BNUndefineAnalysisType(self.handle, name)
+ core.BNUndefineAnalysisType(self.handle, type_id)
def undefine_user_type(self, name):
"""
``undefine_user_type`` removes a :py:Class:`Type` from the global list of user types for the current
:py:Class:`BinaryView`
- :param str name: Name of user type to be undefined
+ :param QualifiedName name: Name of user type to be undefined
:rtype: None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> bv.define_user_type(name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
- >>> bv.undefine_type(name)
+ >>> bv.undefine_user_type(name)
>>> bv.get_type_by_name(name)
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
core.BNUndefineUserAnalysisType(self.handle, name)
+ def rename_type(self, old_name, new_name):
+ """
+ ``rename_type`` renames a type in the global list of types for the current :py:Class:`BinaryView`
+
+ :param QualifiedName old_name: Existing name of type to be renamed
+ :param QualifiedName new_name: New name of type to be renamed
+ :rtype: None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> bv.define_user_type(name, type)
+ >>> bv.get_type_by_name("foo")
+ <type: int32_t>
+ >>> bv.rename_type("foo", "bar")
+ >>> bv.get_type_by_name("bar")
+ <type: int32_t>
+ >>>
+ """
+ old_name = types.QualifiedName(old_name)._get_core_struct()
+ new_name = types.QualifiedName(new_name)._get_core_struct()
+ core.BNRenameAnalysisType(self.handle, old_name, new_name)
+
+ def register_platform_types(self, platform):
+ """
+ ``register_platform_types`` ensures that the platform-specific types for a :py:Class:`Platform` are available
+ for the current :py:Class:`BinaryView`. This is automatically performed when adding a new function or setting
+ the default platform.
+
+ :param Platform platform: Platform containing types to be registered
+ :rtype: None
+ :Example:
+
+ >>> platform = Platform["linux-x86"]
+ >>> bv.register_platform_types(platform)
+ >>>
+ """
+ core.BNRegisterPlatformTypes(self.handle, platform.handle)
+
def find_next_data(self, start, data, flags = 0):
"""
``find_next_data`` searchs for the bytes in data starting at the virtual address ``start`` either, case-sensitive,
@@ -3021,6 +3184,12 @@ class BinaryView(object):
segment.flags)
return result
+ def get_address_for_data_offset(self, offset):
+ address = ctypes.c_ulonglong()
+ if not core.BNGetAddressForDataOffset(self.handle, offset, address):
+ return None
+ return address.value
+
def add_auto_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "",
info_section = "", info_data = 0):
core.BNAddAutoSection(self.handle, name, start, length, type, align, entry_size, linked_section,
@@ -3106,6 +3275,16 @@ class BinaryReader(object):
def __del__(self):
core.BNFreeBinaryReader(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryReader):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryReader):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def endianness(self):
"""
@@ -3413,6 +3592,16 @@ class BinaryWriter(object):
def __del__(self):
core.BNFreeBinaryWriter(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryWriter):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryWriter):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def endianness(self):
"""
diff --git a/python/callingconvention.py b/python/callingconvention.py
index 5f4adeab..04ba711f 100644
--- a/python/callingconvention.py
+++ b/python/callingconvention.py
@@ -112,6 +112,16 @@ class CallingConvention(object):
def __del__(self):
core.BNFreeCallingConvention(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, CallingConvention):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, CallingConvention):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
def _get_caller_saved_regs(self, ctxt, count):
try:
regs = self.__class__.caller_saved_regs
diff --git a/python/demangle.py b/python/demangle.py
index 520cfbaf..ed38674a 100644
--- a/python/demangle.py
+++ b/python/demangle.py
@@ -63,7 +63,7 @@ def demangle_ms(arch, mangled_name):
if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
for i in xrange(outSize.value):
names.append(outName[i])
- core.BNFreeDemangledName(outName.value, outSize.value)
+ core.BNFreeDemangledName(ctypes.byref(outName), outSize.value)
return (types.Type(handle), names)
return (None, mangled_name)
@@ -76,7 +76,7 @@ def demangle_gnu3(arch, mangled_name):
if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)):
for i in xrange(outSize.value):
names.append(outName[i])
- core.BNFreeDemangledName(outName.value, outSize.value)
+ core.BNFreeDemangledName(ctypes.byref(outName), outSize.value)
if not handle:
return (None, names)
return (types.Type(handle), names)
diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py
index 89bc41a1..95e2d62d 100755
--- a/python/examples/export_svg.py
+++ b/python/examples/export_svg.py
@@ -80,6 +80,10 @@ def render_svg(function):
fill: none;
stroke-width: 1px;
}
+ .back_edge {
+ fill: none;
+ stroke-width: 2px;
+ }
.UnconditionalBranch, .IndirectBranch {
stroke: rgb(128, 198, 233);
color: rgb(128, 198, 233);
@@ -197,7 +201,10 @@ def render_svg(function):
points += str(x * widthconst) + "," + str(y * heightconst) + " "
x, y = edge.points[-1]
points += str(x * widthconst) + "," + str(y * heightconst + 0) + " "
- edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=BranchType(edge.type).name, points=points)
+ if edge.back_edge:
+ edges += ' <polyline class="back_edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=BranchType(edge.type).name, points=points)
+ else:
+ edges += ' <polyline class="edge {type}" points="{points}" marker-end="url(#arrow-{type})"/>\n'.format(type=BranchType(edge.type).name, points=points)
output += ' ' + edges + '\n'
output += ' </g>\n'
output += '</svg></html>'
diff --git a/python/examples/version_switcher.py b/python/examples/version_switcher.py
index bc4f576c..9d5bbf05 100644
--- a/python/examples/version_switcher.py
+++ b/python/examples/version_switcher.py
@@ -20,10 +20,12 @@
# IN THE SOFTWARE.
import sys
-import binaryninja
+
+from binaryninja.update import UpdateChannel, are_auto_updates_enabled, set_auto_updates_enabled, is_update_installation_pending, install_pending_update
+from binaryninja import core_version
import datetime
-chandefault = binaryninja.UpdateChannel.list[0].name
+chandefault = UpdateChannel.list[0].name
channel = None
versions = []
@@ -31,17 +33,17 @@ versions = []
def load_channel(newchannel):
global channel
global versions
- if (channel is None and newchannel == channel.name):
+ if (channel is not None and newchannel == channel.name):
print "Same channel, not updating."
else:
try:
print "Loading channel %s" % newchannel
- channel = binaryninja.UpdateChannel[newchannel]
+ channel = UpdateChannel[newchannel]
print "Loading versions..."
versions = channel.versions
except Exception:
print "%s is not a valid channel name. Defaulting to " % chandefault
- channel = binaryninja.UpdateChannel[chandefault]
+ channel = UpdateChannel[chandefault]
def select(version):
@@ -66,16 +68,20 @@ def select(version):
print "Requesting update to latest version."
else:
print "Requesting update to prior version."
- if binaryninja.are_auto_updates_enabled():
+ if are_auto_updates_enabled():
print "Disabling automatic updates."
- binaryninja.set_auto_updates_enabled(False)
- if (version.version == binaryninja.core_version):
+ set_auto_updates_enabled(False)
+ if (version.version == core_version):
print "Already running %s" % version.version
else:
print "version.version %s" % version.version
- print "binaryninja.core_version %s" % binaryninja.core_version
- print "Updating..."
+ print "core_version %s" % core_version
+ print "Downloading..."
print version.update()
+ print "Installing..."
+ if is_update_installation_pending:
+ #note that the GUI will be launched after update but should still do the upgrade headless
+ install_pending_update()
# forward updating won't work without reloading
sys.exit()
else:
@@ -86,7 +92,7 @@ def list_channels():
done = False
print "\tSelect channel:\n"
while not done:
- channel_list = binaryninja.UpdateChannel.list
+ channel_list = UpdateChannel.list
for index, item in enumerate(channel_list):
print "\t%d)\t%s" % (index + 1, item.name)
print "\t%d)\t%s" % (len(channel_list) + 1, "Main Menu")
@@ -104,7 +110,7 @@ def list_channels():
def toggle_updates():
- binaryninja.set_auto_updates_enabled(not binaryninja.are_auto_updates_enabled())
+ set_auto_updates_enabled(not are_auto_updates_enabled())
def main():
@@ -114,8 +120,8 @@ def main():
while not done:
print "\n\tBinary Ninja Version Switcher"
print "\t\tCurrent Channel:\t%s" % channel.name
- print "\t\tCurrent Version:\t%s" % binaryninja.core_version
- print "\t\tAuto-Updates On:\t%s\n" % binaryninja.are_auto_updates_enabled()
+ print "\t\tCurrent Version:\t%s" % core_version
+ print "\t\tAuto-Updates On:\t%s\n" % are_auto_updates_enabled()
for index, version in enumerate(versions):
date = datetime.datetime.fromtimestamp(version.time).strftime('%c')
print "\t%d)\t%s (%s)" % (index + 1, version.version, date)
diff --git a/python/filemetadata.py b/python/filemetadata.py
index f6593405..b489d5bb 100644
--- a/python/filemetadata.py
+++ b/python/filemetadata.py
@@ -93,6 +93,16 @@ class FileMetadata(object):
core.BNSetFileMetadataNavigationHandler(self.handle, None)
core.BNFreeFileMetadata(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, FileMetadata):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, FileMetadata):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@classmethod
def _unregister(cls, f):
handle = ctypes.cast(f, ctypes.c_void_p)
diff --git a/python/function.py b/python/function.py
index 7d03585c..86c93bf7 100644
--- a/python/function.py
+++ b/python/function.py
@@ -26,7 +26,7 @@ import ctypes
import _binaryninjacore as core
from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType,
HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend,
- DisassemblyOption, IntegerDisplayType)
+ DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext)
import architecture
import highlight
import associateddatastore
@@ -177,6 +177,16 @@ class Function(object):
core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests)
core.BNFreeFunction(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, Function):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Function):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@classmethod
def _unregister(cls, func):
handle = ctypes.cast(func, ctypes.c_void_p)
@@ -669,7 +679,9 @@ class Function(object):
value = lines[i].tokens[j].value
size = lines[i].tokens[j].size
operand = lines[i].tokens[j].operand
- tokens.append(InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].tokens[j].context
+ address = lines[i].tokens[j].address
+ tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address))
result.append(tokens)
core.BNFreeInstructionTextLines(lines, count.value)
return result
@@ -764,7 +776,9 @@ class Function(object):
"""
if arch is None:
arch = self.arch
- if not isinstance(color, highlight.HighlightColor):
+ if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
+ raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
+ if isinstance(color, HighlightStandardColor):
color = highlight.HighlightColor(color = color)
core.BNSetAutoInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct())
@@ -784,6 +798,8 @@ class Function(object):
arch = self.arch
if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
+ if isinstance(color, HighlightStandardColor):
+ color = highlight.HighlightColor(color)
core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct())
@@ -831,16 +847,19 @@ class DisassemblyTextLine(object):
class FunctionGraphEdge(object):
- def __init__(self, branch_type, arch, target, points):
+ def __init__(self, branch_type, source, target, points):
self.type = BranchType(branch_type)
- self.arch = arch
+ self.source = source
self.target = target
self.points = points
def __repr__(self):
- if self.arch:
- return "<%s: %s@%#x>" % (self.type.name, self.arch.name, self.target)
- return "<%s: %#x>" % (self.type, self.target)
+ return "<%s: %s>" % (self.type.name, repr(self.target))
+
+ @property
+ def back_edge(self):
+ """Whether the edge is a back edge (end of a loop)"""
+ return self.target in self.source.basic_block.dominators
class FunctionGraphBlock(object):
@@ -850,6 +869,16 @@ class FunctionGraphBlock(object):
def __del__(self):
core.BNFreeFunctionGraphBlock(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, FunctionGraphBlock):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, FunctionGraphBlock):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def basic_block(self):
"""Basic block associated with this part of the function graph (read-only)"""
@@ -916,7 +945,9 @@ class FunctionGraphBlock(object):
value = lines[i].tokens[j].value
size = lines[i].tokens[j].size
operand = lines[i].tokens[j].operand
- tokens.append(InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].tokens[j].context
+ address = lines[i].tokens[j].address
+ tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address))
result.append(DisassemblyTextLine(addr, tokens))
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
@@ -930,13 +961,19 @@ class FunctionGraphBlock(object):
for i in xrange(0, count.value):
branch_type = BranchType(edges[i].type)
target = edges[i].target
- arch = None
- if edges[i].arch is not None:
- arch = architecture.Architecture(edges[i].arch)
+ if target:
+ func = core.BNGetBasicBlockFunction(target)
+ if func is None:
+ core.BNFreeBasicBlock(target)
+ target = None
+ else:
+ target = basicblock.BasicBlock(binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
+ core.BNNewBasicBlockReference(target))
+ core.BNFreeFunction(func)
points = []
for j in xrange(0, edges[i].pointCount):
points.append((edges[i].points[j].x, edges[i].points[j].y))
- result.append(FunctionGraphEdge(branch_type, arch, target, points))
+ result.append(FunctionGraphEdge(branch_type, self, target, points))
core.BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count.value)
return result
@@ -966,7 +1003,9 @@ class FunctionGraphBlock(object):
value = lines[i].tokens[j].value
size = lines[i].tokens[j].size
operand = lines[i].tokens[j].operand
- tokens.append(InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].tokens[j].context
+ address = lines[i].tokens[j].address
+ tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address))
yield DisassemblyTextLine(addr, tokens)
finally:
core.BNFreeDisassemblyTextLines(lines, count.value)
@@ -1020,6 +1059,16 @@ class FunctionGraph(object):
self.abort()
core.BNFreeFunctionGraph(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, FunctionGraph):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, FunctionGraph):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def function(self):
"""Function for a function graph (read-only)"""
@@ -1237,12 +1286,15 @@ class InstructionTextToken(object):
========================== ============================================
"""
- def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff):
+ def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff,
+ context = InstructionTextTokenContext.NoTokenContext, address = 0):
self.type = InstructionTextTokenType(token_type)
self.text = text
self.value = value
self.size = size
self.operand = operand
+ self.context = InstructionTextTokenContext(context)
+ self.address = address
def __str__(self):
return self.text
diff --git a/python/generator.cpp b/python/generator.cpp
index d3725b6d..1c0e7b16 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -97,17 +97,19 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac
else
fprintf(out, "ctypes.c_double");
break;
- case StructureTypeClass:
- fprintf(out, "%s", type->GetQualifiedName(type->GetStructure()->GetName()).c_str());
- break;
- case EnumerationTypeClass:
- {
- string name = type->GetQualifiedName(type->GetEnumeration()->GetName());
- if (name.size() > 2 && name.substr(0, 2) == "BN")
- name = name.substr(2);
- fprintf(out, "%sEnum", name.c_str());
+ case NamedTypeReferenceClass:
+ if (type->GetNamedTypeReference()->GetTypeClass() == EnumNamedTypeClass)
+ {
+ string name = type->GetNamedTypeReference()->GetName().GetString();
+ if (name.size() > 2 && name.substr(0, 2) == "BN")
+ name = name.substr(2);
+ fprintf(out, "%sEnum", name.c_str());
+ }
+ else
+ {
+ fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str());
+ }
break;
- }
case PointerTypeClass:
if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass))
{
@@ -161,7 +163,7 @@ int main(int argc, char* argv[])
Architecture::Register(new GeneratorArchitecture());
// Parse API header to get type and function information
- map<string, Ref<Type>> types, vars, funcs;
+ map<QualifiedName, Ref<Type>> types, vars, funcs;
string errors;
bool ok = Architecture::GetByName("generator")->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors);
fprintf(stderr, "%s", errors.c_str());
@@ -195,14 +197,17 @@ int main(int argc, char* argv[])
fprintf(out, "# Type definitions\n");
for (auto& i : types)
{
+ string name;
+ if (i.first.size() != 1)
+ continue;
+ name = i.first[0];
if (i.second->GetClass() == StructureTypeClass)
{
- fprintf(out, "class %s(ctypes.Structure):\n", i.first.c_str());
+ fprintf(out, "class %s(ctypes.Structure):\n", name.c_str());
fprintf(out, "\tpass\n");
}
else if (i.second->GetClass() == EnumerationTypeClass)
{
- string name = i.first;
if (name.size() > 2 && name.substr(0, 2) == "BN")
name = name.substr(2);
@@ -217,7 +222,7 @@ int main(int argc, char* argv[])
else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) ||
(i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass))
{
- fprintf(out, "%s = ", i.first.c_str());
+ fprintf(out, "%s = ", name.c_str());
OutputType(out, i.second);
fprintf(out, "\n");
}
@@ -227,9 +232,13 @@ int main(int argc, char* argv[])
fprintf(out, "\n# Structure definitions\n");
for (auto& i : types)
{
+ string name;
+ if (i.first.size() != 1)
+ continue;
+ name = i.first[0];
if ((i.second->GetClass() == StructureTypeClass) && (i.second->GetStructure()->GetMembers().size() != 0))
{
- fprintf(out, "%s._fields_ = [\n", i.first.c_str());
+ fprintf(out, "%s._fields_ = [\n", name.c_str());
for (auto& j : i.second->GetStructure()->GetMembers())
{
fprintf(out, "\t\t(\"%s\", ", j.name.c_str());
@@ -243,6 +252,11 @@ int main(int argc, char* argv[])
fprintf(out, "\n# Function definitions\n");
for (auto& i : funcs)
{
+ string name;
+ if (i.first.size() != 1)
+ continue;
+ name = i.first[0];
+
// Check for a string result, these will be automatically wrapped to free the string
// memory and return a Python string
bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass) &&
@@ -251,7 +265,7 @@ int main(int argc, char* argv[])
// Pointer returns will be automatically wrapped to return None on null pointer
bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass);
bool callbackConvention = false;
- if (i.first == "BNAllocString")
+ if (name == "BNAllocString")
{
// Don't perform automatic wrapping of string allocation, and return a void
// pointer so that callback functions (which is the only valid use of BNAllocString)
@@ -260,11 +274,11 @@ int main(int argc, char* argv[])
callbackConvention = true;
}
- string funcName = i.first;
+ string funcName = name;
if (stringResult || pointerResult)
funcName = string("_") + funcName;
- fprintf(out, "%s = core.%s\n", funcName.c_str(), i.first.c_str());
+ fprintf(out, "%s = core.%s\n", funcName.c_str(), name.c_str());
fprintf(out, "%s.restype = ", funcName.c_str());
OutputType(out, i.second->GetChildType(), true, callbackConvention);
fprintf(out, "\n");
@@ -274,7 +288,7 @@ int main(int argc, char* argv[])
for (auto& j : i.second->GetParameters())
{
fprintf(out, "\t\t");
- if (i.first == "BNFreeString")
+ if (name == "BNFreeString")
{
// BNFreeString expects a pointer to a string allocated by the core, so do not use
// a c_char_p here, as that would be allocated by the Python runtime. This can
@@ -293,7 +307,7 @@ int main(int argc, char* argv[])
if (stringResult)
{
// Emit wrapper to get Python string and free native memory
- fprintf(out, "def %s(*args):\n", i.first.c_str());
+ fprintf(out, "def %s(*args):\n", name.c_str());
fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
fprintf(out, "\tstring = ctypes.cast(result, ctypes.c_char_p).value\n");
fprintf(out, "\tBNFreeString(result)\n");
@@ -302,7 +316,7 @@ int main(int argc, char* argv[])
else if (pointerResult)
{
// Emit wrapper to return None on null pointer
- fprintf(out, "def %s(*args):\n", i.first.c_str());
+ fprintf(out, "def %s(*args):\n", name.c_str());
fprintf(out, "\tresult = %s(*args)\n", funcName.c_str());
fprintf(out, "\tif not result:\n");
fprintf(out, "\t\treturn None\n");
diff --git a/python/lowlevelil.py b/python/lowlevelil.py
index 419e8513..c80fcd0d 100644
--- a/python/lowlevelil.py
+++ b/python/lowlevelil.py
@@ -187,7 +187,9 @@ class LowLevelILInstruction(object):
value = tokens[i].value
size = tokens[i].size
operand = tokens[i].operand
- result.append(function.InstructionTextToken(token_type, text, value, size, operand))
+ context = tokens[i].context
+ address = tokens[i].address
+ result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
core.BNFreeInstructionText(tokens, count.value)
return result
@@ -251,6 +253,16 @@ class LowLevelILFunction(object):
def __del__(self):
core.BNFreeLowLevelILFunction(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, LowLevelILFunction):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, LowLevelILFunction):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def current_address(self):
"""Current IL Address (read/write)"""
diff --git a/python/platform.py b/python/platform.py
index 04dce587..139b7d5e 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -25,6 +25,7 @@ import _binaryninjacore as core
import startup
import architecture
import callingconvention
+import types
class _PlatformMetaClass(type):
@@ -109,6 +110,16 @@ class Platform(object):
def __del__(self):
core.BNFreePlatform(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, Platform):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Platform):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def default_calling_convention(self):
"""
@@ -215,6 +226,55 @@ class Platform(object):
core.BNFreeCallingConventionList(cc, count.value)
return result
+ @property
+ def types(self):
+ """List of platform-specific types (read-only)"""
+ count = ctypes.c_ulonglong(0)
+ type_list = core.BNGetPlatformTypes(self.handle, count)
+ result = {}
+ for i in xrange(0, count.value):
+ name = types.QualifiedName._from_core_struct(type_list[i].name)
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ core.BNFreeTypeList(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)
+ result = {}
+ for i in xrange(0, count.value):
+ name = types.QualifiedName._from_core_struct(type_list[i].name)
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ core.BNFreeTypeList(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)
+ result = {}
+ for i in xrange(0, count.value):
+ name = types.QualifiedName._from_core_struct(type_list[i].name)
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ core.BNFreeTypeList(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)
+ result = {}
+ for i in xrange(0, count.value):
+ name = types.QualifiedName._from_core_struct(call_list[i].name)
+ t = types.Type(core.BNNewTypeReference(call_list[i].type))
+ result[call_list[i].number] = (name, t)
+ core.BNFreeSystemCallList(call_list, count.value)
+ return result
+
def __setattr__(self, name, value):
try:
object.__setattr__(self, name, value)
@@ -259,3 +319,44 @@ class Platform(object):
new_addr.value = addr
result = core.BNGetAssociatedPlatformByAddress(self.handle, new_addr)
return Platform(None, handle = result), new_addr.value
+
+ def get_type_by_name(self, name):
+ name = types.QualifiedName(name)._get_core_struct()
+ obj = core.BNGetPlatformTypeByName(self.handle, name)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def get_variable_by_name(self, name):
+ name = types.QualifiedName(name)._get_core_struct()
+ obj = core.BNGetPlatformVariableByName(self.handle, name)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def get_function_by_name(self, name):
+ name = types.QualifiedName(name)._get_core_struct()
+ obj = core.BNGetPlatformFunctionByName(self.handle, name)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def get_system_call_name(self, number):
+ return core.BNGetPlatformSystemCallName(self.handle, number)
+
+ def get_system_call_type(self, number):
+ obj = core.BNGetPlatformSystemCallType(self.handle, number)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def generate_auto_platform_type_id(self, name):
+ name = types.QualifiedName(name)._get_core_struct()
+ return core.BNGenerateAutoPlatformTypeId(self.handle, name)
+
+ def generate_auto_platform_type_ref(self, type_class, name):
+ type_id = self.generate_auto_platform_type_id(name)
+ return types.NamedTypeReference(type_class, type_id, name)
+
+ def get_auto_platform_type_id_source(self):
+ return core.BNGetAutoPlatformTypeIdSource(self.handle)
diff --git a/python/plugin.py b/python/plugin.py
index 9a4da487..2632b5a9 100644
--- a/python/plugin.py
+++ b/python/plugin.py
@@ -24,7 +24,7 @@ import threading
# Binary Ninja components
import _binaryninjacore as core
-from enums import LowLevelILOperation
+from enums import PluginCommandType
import startup
import filemetadata
import binaryview
@@ -78,7 +78,7 @@ class PluginCommand(object):
ctypes.memmove(ctypes.byref(self.command), ctypes.byref(cmd), ctypes.sizeof(core.BNPluginCommand))
self.name = str(cmd.name)
self.description = str(cmd.description)
- self.type = LowLevelILOperation(cmd.type)
+ self.type = PluginCommandType(cmd.type)
@classmethod
def _default_action(cls, view, action):
@@ -210,21 +210,21 @@ class PluginCommand(object):
def is_valid(self, context):
if context.view is None:
return False
- if self.command.type == LowLevelILOperation.DefaultPluginCommand:
+ if self.command.type == PluginCommandType.DefaultPluginCommand:
if not self.command.defaultIsValid:
return True
return self.command.defaultIsValid(self.command.context, context.view.handle)
- elif self.command.type == LowLevelILOperation.AddressPluginCommand:
+ elif self.command.type == PluginCommandType.AddressPluginCommand:
if not self.command.addressIsValid:
return True
return self.command.addressIsValid(self.command.context, context.view.handle, context.address)
- elif self.command.type == LowLevelILOperation.RangePluginCommand:
+ elif self.command.type == PluginCommandType.RangePluginCommand:
if context.length == 0:
return False
if not self.command.rangeIsValid:
return True
return self.command.rangeIsValid(self.command.context, context.view.handle, context.address, context.length)
- elif self.command.type == LowLevelILOperation.FunctionPluginCommand:
+ elif self.command.type == PluginCommandType.FunctionPluginCommand:
if context.function is None:
return False
if not self.command.functionIsValid:
@@ -235,13 +235,13 @@ class PluginCommand(object):
def execute(self, context):
if not self.is_valid(context):
return
- if self.command.type == LowLevelILOperation.DefaultPluginCommand:
+ if self.command.type == PluginCommandType.DefaultPluginCommand:
self.command.defaultCommand(self.command.context, context.view.handle)
- elif self.command.type == LowLevelILOperation.AddressPluginCommand:
+ elif self.command.type == PluginCommandType.AddressPluginCommand:
self.command.addressCommand(self.command.context, context.view.handle, context.address)
- elif self.command.type == LowLevelILOperation.RangePluginCommand:
+ elif self.command.type == PluginCommandType.RangePluginCommand:
self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length)
- elif self.command.type == LowLevelILOperation.FunctionPluginCommand:
+ elif self.command.type == PluginCommandType.FunctionPluginCommand:
self.command.functionCommand(self.command.context, context.view.handle, context.function.handle)
def __repr__(self):
diff --git a/python/transform.py b/python/transform.py
index 0c003738..40382c69 100644
--- a/python/transform.py
+++ b/python/transform.py
@@ -131,6 +131,16 @@ class Transform(object):
def __repr__(self):
return "<transform: %s>" % self.name
+ def __eq__(self, value):
+ if not isinstance(value, Transform):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Transform):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
def _get_parameters(self, ctxt, count):
try:
count[0] = len(self.parameters)
diff --git a/python/types.py b/python/types.py
index 8582e4e0..ebaa36fc 100644
--- a/python/types.py
+++ b/python/types.py
@@ -22,9 +22,92 @@ import ctypes
# Binary Ninja components
import _binaryninjacore as core
-from enums import SymbolType, TypeClass
+from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType
import callingconvention
-import demangle
+import function
+
+
+class QualifiedName(object):
+ def __init__(self, name = []):
+ if isinstance(name, str):
+ self.name = [name]
+ elif isinstance(name, QualifiedName):
+ self.name = name.name
+ else:
+ self.name = name
+
+ def __str__(self):
+ return "::".join(self.name)
+
+ def __repr__(self):
+ return repr(str(self))
+
+ def __len__(self):
+ return len(self.name)
+
+ def __hash__(self):
+ return hash(str(self))
+
+ def __eq__(self, other):
+ if isinstance(other, str):
+ return str(self) == other
+ elif isinstance(other, list):
+ return self.name == other
+ elif isinstance(other, QualifiedName):
+ return self.name == other.name
+ return False
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __lt__(self, other):
+ if isinstance(other, QualifiedName):
+ return self.name < other.name
+ return False
+
+ def __le__(self, other):
+ if isinstance(other, QualifiedName):
+ return self.name <= other.name
+ return False
+
+ def __gt__(self, other):
+ if isinstance(other, QualifiedName):
+ return self.name > other.name
+ return False
+
+ def __ge__(self, other):
+ if isinstance(other, QualifiedName):
+ return self.name >= other.name
+ return False
+
+ def __cmp__(self, other):
+ if self == other:
+ return 0
+ if self < other:
+ return -1
+ return 1
+
+ def __getitem__(self, key):
+ return self.name[key]
+
+ def __iter__(self):
+ return iter(self.name)
+
+ def _get_core_struct(self):
+ result = core.BNQualifiedName()
+ name_list = (ctypes.c_char_p * len(self.name))()
+ for i in xrange(0, len(self.name)):
+ name_list[i] = self.name[i]
+ result.name = name_list
+ result.nameCount = len(self.name)
+ return result
+
+ @classmethod
+ def _from_core_struct(cls, name):
+ result = []
+ for i in xrange(0, name.nameCount):
+ result.append(name.name[i])
+ return QualifiedName(result)
class Symbol(object):
@@ -56,6 +139,16 @@ class Symbol(object):
def __del__(self):
core.BNFreeSymbol(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, Symbol):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Symbol):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def type(self):
"""Symbol type (read-only)"""
@@ -111,6 +204,16 @@ class Type(object):
def __del__(self):
core.BNFreeType(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, Type):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, Type):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def type_class(self):
"""Type class (read-only)"""
@@ -210,6 +313,14 @@ class Type(object):
return None
return Enumeration(result)
+ @property
+ def named_type_reference(self):
+ """Reference to a named type (read-only)"""
+ result = core.BNGetTypeNamedTypeReference(self.handle)
+ if result is None:
+ return None
+ return NamedTypeReference(handle = result)
+
@property
def count(self):
"""Type count (read-only)"""
@@ -227,6 +338,56 @@ class Type(object):
def get_string_after_name(self):
return core.BNGetTypeStringAfterName(self.handle)
+ @property
+ def tokens(self):
+ """Type string as a list of tokens (read-only)"""
+ count = ctypes.c_ulonglong()
+ tokens = core.BNGetTypeTokens(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ token_type = InstructionTextTokenType(tokens[i].type)
+ text = tokens[i].text
+ value = tokens[i].value
+ size = tokens[i].size
+ operand = tokens[i].operand
+ context = tokens[i].context
+ address = tokens[i].address
+ result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
+ core.BNFreeTokenList(tokens, count.value)
+ return result
+
+ def get_tokens_before_name(self):
+ count = ctypes.c_ulonglong()
+ tokens = core.BNGetTypeTokensBeforeName(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ token_type = InstructionTextTokenType(tokens[i].type)
+ text = tokens[i].text
+ value = tokens[i].value
+ size = tokens[i].size
+ operand = tokens[i].operand
+ context = tokens[i].context
+ address = tokens[i].address
+ result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
+ core.BNFreeTokenList(tokens, count.value)
+ return result
+
+ def get_tokens_after_name(self):
+ count = ctypes.c_ulonglong()
+ tokens = core.BNGetTypeTokensAfterName(self.handle, count)
+ result = []
+ for i in xrange(0, count.value):
+ token_type = InstructionTextTokenType(tokens[i].type)
+ text = tokens[i].text
+ value = tokens[i].value
+ size = tokens[i].size
+ operand = tokens[i].operand
+ context = tokens[i].context
+ address = tokens[i].address
+ result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
+ core.BNFreeTokenList(tokens, count.value)
+ return result
+
@classmethod
def void(cls):
return Type(core.BNCreateVoidType())
@@ -237,6 +398,12 @@ class Type(object):
@classmethod
def int(self, width, sign = True, altname=""):
+ """
+ ``int`` class method for creating an int Type.
+
+ :param int width: width of the integer in bytes
+ :param bool sign: optional variable representing signedness
+ """
return Type(core.BNCreateIntegerType(width, sign, altname))
@classmethod
@@ -248,8 +415,27 @@ class Type(object):
return Type(core.BNCreateStructureType(structure_type.handle))
@classmethod
- def unknown_type(self, unknown_type):
- return Type(core.BNCreateUnknownType(unknown_type.handle))
+ def named_type(self, named_type, width = 0, align = 1):
+ return Type(core.BNCreateNamedTypeReference(named_type.handle, width, align))
+
+ @classmethod
+ def named_type_from_type_and_id(self, type_id, name, t):
+ name = QualifiedName(name)._get_core_struct()
+ if t is not None:
+ t = t.handle
+ return Type(core.BNCreateNamedTypeReferenceFromTypeAndId(type_id, name, t))
+
+ @classmethod
+ def named_type_from_type(self, name, t):
+ name = QualifiedName(name)._get_core_struct()
+ if t is not None:
+ t = t.handle
+ return Type(core.BNCreateNamedTypeReferenceFromTypeAndId("", name, t))
+
+ @classmethod
+ def named_type_from_registered_type(self, view, name):
+ name = QualifiedName(name)._get_core_struct()
+ return Type(core.BNCreateNamedTypeReferenceFromType(view.handle, name))
@classmethod
def enumeration_type(self, arch, e, width=None):
@@ -267,6 +453,14 @@ class Type(object):
@classmethod
def function(self, ret, params, calling_convention=None, variable_arguments=False):
+ """
+ ``function`` class method for creating an function Type.
+
+ :param Type ret: width of the integer in bytes
+ :param list(Type) params: list of parameter Types
+ :param CallingConvention calling_convention: optional argument for function calling convention
+ :param bool variable_arguments: optional argument for functions that have a variable number of arguments
+ """
param_buf = (core.BNNameAndType * len(params))()
for i in xrange(0, len(params)):
if isinstance(params[i], Type):
@@ -280,6 +474,20 @@ class Type(object):
return Type(core.BNCreateFunctionType(ret.handle, calling_convention, param_buf, len(params),
variable_arguments))
+ @classmethod
+ def generate_auto_type_id(self, source, name):
+ name = QualifiedName(name)._get_core_struct()
+ return core.BNGenerateAutoTypeId(source, name)
+
+ @classmethod
+ def generate_auto_demangled_type_id(self, name):
+ name = QualifiedName(name)._get_core_struct()
+ return core.BNGenerateAutoDemangledTypeId(name)
+
+ @classmethod
+ def get_auto_demanged_type_id_source(self):
+ return core.BNGetAutoDemangledTypeIdSource()
+
def __setattr__(self, name, value):
try:
object.__setattr__(self, name, value)
@@ -287,28 +495,80 @@ class Type(object):
raise AttributeError("attribute '%s' is read only" % name)
-class UnknownType(object):
- def __init__(self, handle=None):
+class NamedTypeReference(object):
+ def __init__(self, type_class = NamedTypeReferenceClass.UnknownNamedTypeClass, type_id = None, name = None, handle = None):
if handle is None:
- self.handle = core.BNCreateUnknownType()
+ self.handle = core.BNCreateNamedType()
+ core.BNSetTypeReferenceClass(self.handle, type_class)
+ if type_id is not None:
+ core.BNSetTypeReferenceId(self.handle, type_id)
+ if name is not None:
+ name = QualifiedName(name)._get_core_struct()
+ core.BNSetTypeReferenceName(self.handle, name)
else:
self.handle = handle
def __del__(self):
- core.BNFreeUnknownType(self.handle)
+ core.BNFreeNamedTypeReference(self.handle)
+
+ def __eq__(self, value):
+ if not isinstance(value, NamedTypeReference):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, NamedTypeReference):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
+ @property
+ def type_class(self):
+ return NamedTypeReferenceClass(core.BNGetTypeReferenceClass(self.handle))
+
+ @type_class.setter
+ def type_class(self, value):
+ core.BNSetTypeReferenceClass(self.handle, value)
+
+ @property
+ def type_id(self):
+ return core.BNGetTypeReferenceId(self.handle)
+
+ @type_id.setter
+ def type_id(self, value):
+ core.BNSetTypeReferenceId(self.handle, value)
@property
def name(self):
- count = ctypes.c_ulonglong()
- nameList = core.BNGetUnknownTypeName(self.handle, count)
- result = []
- for i in xrange(count.value):
- result.append(nameList[i])
- return demangle.get_qualified_name(result)
+ name = core.BNGetTypeReferenceName(self.handle)
+ result = QualifiedName._from_core_struct(name)
+ core.BNFreeQualifiedName(name)
+ return result
@name.setter
def name(self, value):
- core.BNSetUnknownTypeName(self.handle, value)
+ value = QualifiedName(value)._get_core_struct()
+ core.BNSetTypeReferenceName(self.handle, value)
+
+ def __repr__(self):
+ if self.type_class == NamedTypeReferenceClass.TypedefNamedTypeClass:
+ return "<named type: typedef %s>" % str(self.name)
+ if self.type_class == NamedTypeReferenceClass.StructNamedTypeClass:
+ return "<named type: struct %s>" % str(self.name)
+ if self.type_class == NamedTypeReferenceClass.UnionNamedTypeClass:
+ return "<named type: union %s>" % str(self.name)
+ if self.type_class == NamedTypeReferenceClass.EnumNamedTypeClass:
+ return "<named type: enum %s>" % str(self.name)
+ return "<named type: unknown %s>" % str(self.name)
+
+ @classmethod
+ def generate_auto_type_ref(self, type_class, source, name):
+ type_id = Type.generate_auto_type_id(source, name)
+ return NamedTypeReference(type_class, type_id, name)
+
+ @classmethod
+ def generate_auto_demangled_type_ref(self, type_class, name):
+ type_id = Type.generate_auto_demangled_type_id(name)
+ return NamedTypeReference(type_class, type_id, name)
class StructureMember(object):
@@ -334,18 +594,15 @@ class Structure(object):
def __del__(self):
core.BNFreeStructure(self.handle)
- @property
- def name(self):
- count = ctypes.c_ulonglong()
- nameList = core.BNGetStructureName(self.handle, count)
- result = []
- for i in xrange(count.value):
- result.append(nameList[i])
- return demangle.get_qualified_name(result)
+ def __eq__(self, value):
+ if not isinstance(value, Structure):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
- @name.setter
- def name(self, value):
- core.BNSetStructureName(self.handle, value)
+ def __ne__(self, value):
+ if not isinstance(value, Structure):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
@property
def members(self):
@@ -361,14 +618,22 @@ class Structure(object):
@property
def width(self):
- """Structure width (read-only)"""
+ """Structure width"""
return core.BNGetStructureWidth(self.handle)
+ @width.setter
+ def width(self, new_width):
+ core.BNSetStructureWidth(self.handle, new_width)
+
@property
def alignment(self):
- """Structure alignment (read-only)"""
+ """Structure alignment"""
return core.BNGetStructureAlignment(self.handle)
+ @alignment.setter
+ def alignment(self, align):
+ core.BNSetStructureAlignment(self.handle, align)
+
@property
def packed(self):
return core.BNIsStructurePacked(self.handle)
@@ -392,8 +657,6 @@ class Structure(object):
raise AttributeError("attribute '%s' is read only" % name)
def __repr__(self):
- if len(self.name) > 0:
- return "<struct: %s>" % self.name
return "<struct: size %#x>" % self.width
def append(self, t, name = ""):
@@ -405,6 +668,9 @@ class Structure(object):
def remove(self, i):
core.BNRemoveStructureMember(self.handle, i)
+ def replace(self, i, t, name = ""):
+ core.BNReplaceStructureMember(self.handle, i, t.handle, name)
+
class EnumerationMember(object):
def __init__(self, name, value, default):
@@ -426,13 +692,15 @@ class Enumeration(object):
def __del__(self):
core.BNFreeEnumeration(self.handle)
- @property
- def name(self):
- return core.BNGetEnumerationName(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, Enumeration):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
- @name.setter
- def name(self, value):
- core.BNSetEnumerationName(self.handle, value)
+ def __ne__(self, value):
+ if not isinstance(value, Enumeration):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
@property
def members(self):
@@ -452,8 +720,6 @@ class Enumeration(object):
raise AttributeError("attribute '%s' is read only" % name)
def __repr__(self):
- if len(self.name) > 0:
- return "<enum: %s>" % self.name
return "<enum: %s>" % repr(self.members)
def append(self, name, value = None):
@@ -462,6 +728,12 @@ class Enumeration(object):
else:
core.BNAddEnumerationMemberWithValue(self.handle, name, value)
+ def remove(self, i):
+ core.BNRemoveEnumerationMember(self.handle, i)
+
+ def replace(self, i, name, value):
+ core.BNReplaceEnumerationMember(self.handle, i, name, value)
+
class TypeParserResult(object):
def __init__(self, types, variables, functions):
diff --git a/python/update.py b/python/update.py
index 7e2bd4ef..6417e4a0 100644
--- a/python/update.py
+++ b/python/update.py
@@ -238,5 +238,29 @@ def get_time_since_last_update_check():
return core.BNGetTimeSinceLastUpdateCheck()
+def is_update_installation_pending():
+ """
+ ``is_update_installation_pending`` whether an update has been downloaded and is waiting installation
+
+ :return: boolean True if an update is pending, false if no update is pending
+ :rtype: bool
+ """
+ return core.BNIsUpdateInstallationPending()
+
+
+def install_pending_update():
+ """
+ ``install_pending_update`` installs any pending updates
+
+ :rtype: None
+ """
+ errors = ctypes.c_char_p()
+ core.BNInstallPendingUpdate(errors)
+ if errors:
+ error_str = errors.value
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise IOError(error_str)
+
+
def updates_checked():
core.BNUpdatesChecked()