summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py1
-rw-r--r--python/binaryview.py35
-rw-r--r--python/databuffer.py4
-rw-r--r--python/examples/pseudo_python.py1100
-rw-r--r--python/function.py77
-rw-r--r--python/highlevelil.py4
-rw-r--r--python/languagerepresentation.py822
-rw-r--r--python/lineardisassembly.py10
-rw-r--r--python/scriptingprovider.py18
-rw-r--r--python/types.py67
-rw-r--r--python/variable.py10
11 files changed, 2118 insertions, 30 deletions
diff --git a/python/__init__.py b/python/__init__.py
index 84494296..b6a3de97 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -79,6 +79,7 @@ from .debuginfo import *
from .externallibrary import *
from .undo import *
from .fileaccessor import *
+from .languagerepresentation import *
# We import each of these by name to prevent conflicts between
# log.py and the function 'log' which we don't import below
from .log import (
diff --git a/python/binaryview.py b/python/binaryview.py
index fe270c9a..6adb8b1e 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -8545,7 +8545,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
def find_next_text(
self, start: int, text: str, settings: Optional[_function.DisassemblySettings] = None,
flags: FindFlag = FindFlag.FindCaseSensitive,
- graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph
+ graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph
) -> Optional[int]:
"""
``find_next_text`` searches for string ``text`` occurring in the linear view output starting at the virtual
@@ -8562,7 +8562,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
FindCaseSensitive Case-sensitive search
FindCaseInsensitive Case-insensitive search
==================== ============================
- :param FunctionGraphType graph_type: the IL to search within
+ :param FunctionViewType graph_type: the IL to search within
"""
if not isinstance(text, str):
raise TypeError("text parameter is not str type")
@@ -8572,13 +8572,14 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
raise TypeError("settings parameter is not DisassemblySettings type")
result = ctypes.c_ulonglong()
+ graph_type = _function.FunctionViewType(graph_type)._to_core_struct()
if not core.BNFindNextText(self.handle, start, text, result, settings.handle, flags, graph_type):
return None
return result.value
def find_next_constant(
self, start: int, constant: int, settings: Optional[_function.DisassemblySettings] = None,
- graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph
+ graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph
) -> Optional[int]:
"""
``find_next_constant`` searches for integer constant ``constant`` occurring in the linear view output starting at the virtual
@@ -8587,7 +8588,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
:param int start: virtual address to start searching from.
:param int constant: constant to search for
:param DisassemblySettings settings: disassembly settings
- :param FunctionGraphType graph_type: the IL to search within
+ :param FunctionViewType graph_type: the IL to search within
"""
if not isinstance(constant, int):
raise TypeError("constant parameter is not integral type")
@@ -8597,6 +8598,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
raise TypeError("settings parameter is not DisassemblySettings type")
result = ctypes.c_ulonglong()
+ graph_type = _function.FunctionViewType(graph_type)._to_core_struct()
if not core.BNFindNextConstant(self.handle, start, constant, result, settings.handle, graph_type):
return None
return result.value
@@ -8706,7 +8708,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
def find_all_text(
self, start: int, end: int, text: str, settings: Optional[_function.DisassemblySettings] = None,
- flags=FindFlag.FindCaseSensitive, graph_type=FunctionGraphType.NormalFunctionGraph, progress_func=None,
+ flags=FindFlag.FindCaseSensitive, graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func=None,
match_callback=None
) -> QueueGenerator:
"""
@@ -8727,7 +8729,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
FindCaseSensitive Case-sensitive search
FindCaseInsensitive Case-insensitive search
==================== ============================
- :param FunctionGraphType graph_type: the IL to search within
+ :param FunctionViewType graph_type: the IL to search within
:param callback progress_func: optional function to be called with the current progress \
and total count. This function should return a boolean value that decides whether the \
search should continue or stop
@@ -8752,6 +8754,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
raise TypeError("settings parameter is not DisassemblySettings type")
if not isinstance(flags, FindFlag):
raise TypeError('flag parameter must have type FindFlag')
+ graph_type = _function.FunctionViewType(graph_type)._to_core_struct()
if progress_func:
progress_func_obj = ctypes.CFUNCTYPE(
@@ -8799,7 +8802,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
def find_all_constant(
self, start: int, end: int, constant: int, settings: Optional[_function.DisassemblySettings] = None,
- graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph, progress_func: Optional[ProgressFuncType] = None,
+ graph_type: _function.FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph, progress_func: Optional[ProgressFuncType] = None,
match_callback: Optional[LineMatchCallbackType] = None
) -> QueueGenerator:
"""
@@ -8817,7 +8820,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
:param int constant: constant to search for
:param DisassemblySettings settings: DisassemblySettings object used to render the text \
to be searched
- :param FunctionGraphType graph_type: the IL to search within
+ :param FunctionViewType graph_type: the IL to search within
:param callback progress_func: optional function to be called with the current progress \
and total count. This function should return a boolean value that decides whether the \
search should continue or stop
@@ -8839,6 +8842,7 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
settings.set_option(DisassemblyOption.WaitForIL, True)
if not isinstance(settings, _function.DisassemblySettings):
raise TypeError("settings parameter is not DisassemblySettings type")
+ graph_type = _function.FunctionViewType(graph_type)._to_core_struct()
if progress_func:
progress_func_obj = ctypes.CFUNCTYPE(
@@ -9628,6 +9632,21 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
def memory_map(self):
return MemoryMap(handle=self.handle)
+ def stringify_unicode_data(
+ self, arch: Optional['architecture.Architecture'], buffer: 'databuffer.DataBuffer',
+ allow_short_strings: bool = False
+ ) -> Tuple[Optional[str], Optional[StringType]]:
+ string = ctypes.c_char_p()
+ string_type = ctypes.c_int()
+ if arch is not None:
+ arch = arch.handle
+ if not core.BNStringifyUnicodeData(
+ self.handle, arch, buffer.handle, allow_short_strings, ctypes.byref(string), ctypes.byref(string_type)):
+ return None, None
+ result = string.value
+ core.BNFreeString(string)
+ return result, StringType(string_type.value)
+
class BinaryReader:
"""
``class BinaryReader`` is a convenience class for reading binary data.
diff --git a/python/databuffer.py b/python/databuffer.py
index ce8a68e7..36cf4430 100644
--- a/python/databuffer.py
+++ b/python/databuffer.py
@@ -143,8 +143,8 @@ class DataBuffer:
return False
return bytes(self) == bytes(other)
- def escape(self, null_terminates=False) -> str:
- return core.BNDataBufferToEscapedString(self.handle, null_terminates)
+ def escape(self, null_terminates=False, escape_printable=False) -> str:
+ return core.BNDataBufferToEscapedString(self.handle, null_terminates, escape_printable)
def unescape(self) -> 'DataBuffer':
return DataBuffer(handle=core.BNDecodeEscapedString(str(self)))
diff --git a/python/examples/pseudo_python.py b/python/examples/pseudo_python.py
new file mode 100644
index 00000000..b68b4786
--- /dev/null
+++ b/python/examples/pseudo_python.py
@@ -0,0 +1,1100 @@
+# Copyright (c) 2024 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.
+
+from binaryninja import (Architecture, BraceRequirement, DisassemblySettings, DisassemblyTextLine, Function,
+ InstructionTextToken, InstructionTextTokenType, LanguageRepresentationFunction,
+ LanguageRepresentationFunctionType, HighLevelILInstruction, HighLevelILFunction,
+ HighLevelILTokenEmitter, HighLevelILOperation, OperatorPrecedence, ScopeType,
+ SymbolDisplayType, SymbolDisplayResult, SymbolType, BoolType, VoidType, PointerType,
+ NamedTypeReferenceType, StructureType, InstructionTextTokenContext, StructureMember,
+ BinaryView, BuiltinType)
+from typing import Optional
+import struct
+
+
+class PseudoPythonFunction(LanguageRepresentationFunction):
+ comment_start_string = "# "
+
+ def perform_init_token_emitter(self, emitter):
+ # Python never allows braces, even if the user has set the option to show them
+ emitter.brace_requirement = BraceRequirement.BracesNotAllowed
+
+ def perform_begin_lines(self, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter):
+ # Ensure that the function body is indented relative to the function declaration
+ tokens.increase_indent()
+
+ def perform_get_expr_text(
+ self, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter, settings: Optional[DisassemblySettings],
+ as_full_ast: bool = True, precedence: OperatorPrecedence = OperatorPrecedence.TopLevelOperatorPrecedence,
+ statement: bool = False
+ ):
+ with tokens.expr(instr):
+ if instr.operation == HighLevelILOperation.HLIL_BLOCK:
+ need_separator = False
+ body = instr.body
+ # Emit the lines for each statement in the body
+ for (idx, i) in enumerate(body):
+ # Don't display trailing return statements that don't have values
+ if (as_full_ast and idx + 1 == len(body) and i.operation == HighLevelILOperation.HLIL_RET and
+ len(i.src) == 0 and instr.expr_index == self.hlil.root.expr_index):
+ continue
+
+ # If the statement is one that contains additional blocks of code, insert a scope separator
+ # to visually separate the logic.
+ has_blocks = i.operation in [HighLevelILOperation.HLIL_IF, HighLevelILOperation.HLIL_WHILE,
+ HighLevelILOperation.HLIL_DO_WHILE, HighLevelILOperation.HLIL_FOR,
+ HighLevelILOperation.HLIL_SWITCH]
+ if need_separator or (idx != 0 and has_blocks):
+ tokens.scope_separator()
+ need_separator = has_blocks
+
+ # Emit the lines for the statement itself
+ self.perform_get_expr_text(i, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.new_line()
+ elif instr.operation == HighLevelILOperation.HLIL_IF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "if "))
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":\n"))
+ if as_full_ast:
+ # Only display the if body when printing the full AST. When printing basic blocks in graph view,
+ # the body of the if and the else part are rendered as other nodes in the graph.
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.true, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+
+ # Else statements need to be handled as chains, since "else if" in Python should be rendered
+ # as "elif" statements.
+ if_chain = instr.false
+ while if_chain is not None and if_chain.operation not in [HighLevelILOperation.HLIL_NOP,
+ HighLevelILOperation.HLIL_UNREACHABLE]:
+ if if_chain.operation == HighLevelILOperation.HLIL_IF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "elif "))
+ self.perform_get_expr_text(if_chain.condition, tokens, settings, as_full_ast)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(if_chain.true, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ if_chain = if_chain.false
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "else"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(if_chain, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ break
+ elif instr.operation == HighLevelILOperation.HLIL_FOR:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "for "))
+
+ # If the for loop can be represented as a Python range function, show it that way
+ dest_var = None
+ if instr.init.operation == HighLevelILOperation.HLIL_VAR_INIT:
+ dest_var = instr.init.dest
+ elif instr.init.operation == HighLevelILOperation.HLIL_ASSIGN and instr.init.dest.operation == HighLevelILOperation.HLIL_VAR:
+ dest_var = instr.init.dest.var
+ if (dest_var is not None and
+ (instr.condition.operation in [HighLevelILOperation.HLIL_CMP_SLT,
+ HighLevelILOperation.HLIL_CMP_ULT]) and
+ instr.condition.left.operation == HighLevelILOperation.HLIL_VAR and
+ instr.condition.left.var == dest_var and
+ instr.update.operation == HighLevelILOperation.HLIL_ASSIGN and
+ instr.update.dest.operation == HighLevelILOperation.HLIL_VAR and
+ instr.update.dest.var == instr.condition.left.var and
+ instr.update.src.operation == HighLevelILOperation.HLIL_ADD and
+ instr.update.src.left.operation == HighLevelILOperation.HLIL_VAR and
+ instr.update.src.left.var == instr.condition.left.var):
+ step_by = (instr.update.src.right.operation != HighLevelILOperation.HLIL_CONST or
+ instr.update.src.right.constant != 1)
+ start_required = (instr.init.src.operation != HighLevelILOperation.HLIL_CONST or
+ instr.init.src.constant != 0 or step_by)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.LocalVariableToken, dest_var.name,
+ context=InstructionTextTokenContext.LocalVariableTokenContext,
+ address=instr.expr_index, value=dest_var.identifier,
+ size=instr.size))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, " in "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "range"))
+ tokens.append_open_paren()
+ if start_required:
+ self.perform_get_expr_text(instr.init.src, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.condition.right, tokens, settings)
+ if step_by:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.update.src.right, tokens, settings)
+ tokens.append_close_paren()
+ else:
+ # Not representable directly as a Python loop, emit it with a more HLIL-like syntax
+ if instr.init.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.init, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "; "))
+ if instr.condition.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "; "))
+ if instr.update.operation != HighLevelILOperation.HLIL_NOP:
+ self.perform_get_expr_text(instr.update, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_WHILE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "while "))
+ self.perform_get_expr_text(instr.condition, tokens, settings, as_full_ast)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_DO_WHILE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "do"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.BlockScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.BlockScopeType)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "while "))
+ self.perform_get_expr_text(instr.condition, tokens, settings, as_full_ast)
+ elif instr.operation == HighLevelILOperation.HLIL_SWITCH:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "match "))
+ self.perform_get_expr_text(instr.condition, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, ":"))
+ tokens.begin_scope(ScopeType.SwitchScopeType)
+
+ # Output each case
+ for case in instr.cases:
+ self.perform_get_expr_text(case, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.new_line()
+
+ # Check for default case
+ if instr.default is not None and instr.default.operation not in [HighLevelILOperation.HLIL_NOP,
+ HighLevelILOperation.HLIL_UNREACHABLE]:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "default"))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.CaseScopeType)
+ self.perform_get_expr_text(instr.default, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.CaseScopeType)
+ tokens.end_scope(ScopeType.SwitchScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_CASE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "case "))
+ for (i, value) in enumerate(instr.values):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " | "))
+ self.perform_get_expr_text(value, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.begin_scope(ScopeType.CaseScopeType)
+ self.perform_get_expr_text(instr.body, tokens, settings, as_full_ast,
+ OperatorPrecedence.TopLevelOperatorPrecedence, True)
+ tokens.end_scope(ScopeType.CaseScopeType)
+ elif instr.operation == HighLevelILOperation.HLIL_BREAK:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "break"))
+ elif instr.operation == HighLevelILOperation.HLIL_CONTINUE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "continue"))
+ elif instr.operation == HighLevelILOperation.HLIL_CALL:
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_TAILCALL:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "return "))
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, " # tailcall"))
+ elif instr.operation == HighLevelILOperation.HLIL_INTRINSIC:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, instr.intrinsic.name))
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SYSCALL:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "syscall"))
+ tokens.append_open_paren()
+ for (i, param) in enumerate(instr.params):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ if i == 0 and param.operation == HighLevelILOperation.HLIL_CONST:
+ platform = self.function.platform
+ if platform is not None:
+ syscall_name = platform.get_system_call_name(param.constant)
+ if len(syscall_name) > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, syscall_name))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "{"))
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "}"))
+ continue
+ self.perform_get_expr_text(param, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ZX:
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_SX:
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_IMPORT:
+ # Check for import address symbol at target address, and display that if there is one
+ sym = instr.function.source_function.view.get_symbol_at(instr.constant)
+ if sym is not None:
+ if sym.type == SymbolType.ImportedDataSymbol or sym.type == SymbolType.ImportAddressSymbol:
+ sym = sym.imported_function_from_import_address_symbol(instr.constant)
+ if sym is not None:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IndirectImportToken, sym.short_name,
+ value=instr.constant, address=instr.address,
+ size=instr.size, operand=instr.source_operand))
+ return
+ # Otherwise use a generic pointer token
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.DereferenceNonDataSymbols, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_ARRAY_INDEX:
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ tokens.append_open_bracket()
+ self.perform_get_expr_text(instr.index, tokens, settings)
+ tokens.append_close_bracket()
+ elif instr.operation == HighLevelILOperation.HLIL_VAR_INIT:
+ # Check to see if the variable appears live
+ appears_dead = False
+ ssa = instr.ssa_form
+ if ssa is not None and ssa.operation == HighLevelILOperation.HLIL_VAR_INIT_SSA:
+ appears_dead = not self.hlil.is_ssa_var_live(ssa.dest)
+
+ # If the variable does not appear live, show the assignment as zero confidence (grayed out)
+ with tokens.force_zero_confidence(appears_dead):
+ tokens.append_var_text_token(instr.dest, instr, instr.size)
+ if instr.dest.type is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ tokens.append(instr.dest.type.get_tokens())
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+
+ # For the right side of the assignment, only use zero confidence if the instruction does
+ # not have any side effects
+ with tokens.force_zero_confidence(appears_dead and not instr.src.has_side_effects):
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_VAR_DECLARE:
+ tokens.append_var_text_token(instr.var, instr, instr.size)
+ if instr.var.type is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ tokens.append(instr.var.type.get_tokens())
+ elif instr.operation == HighLevelILOperation.HLIL_FLOAT_CONST:
+ # The constant value in the instruction contains the raw bits of the floating point value. Convert
+ # this to a floating point value and display it.
+ if instr.size == 4:
+ value = struct.unpack("<f", struct.pack("<I", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ elif instr.size == 8:
+ value = struct.unpack("<d", struct.pack("<Q", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ else:
+ tokens.append_integer_text_token(instr, instr.constant, instr.size)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST:
+ # Check for bool type. Display these as True or False. The default handling will use C style
+ # booleans instead of Python style.
+ if instr.size == 0 or isinstance(instr.expr_type, BoolType):
+ if instr.constant != 0:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IntegerToken, "True", address=instr.address,
+ value=instr.constant))
+ else:
+ tokens.append(
+ InstructionTextToken(InstructionTextTokenType.IntegerToken, "False", address=instr.address,
+ value=instr.constant))
+ else:
+ tokens.append_constant_text_token(instr, instr.constant, instr.size, settings, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.AddressOfDataSymbols, precedence)
+ elif instr.operation == HighLevelILOperation.HLIL_CONST_DATA:
+ # Constant data should be rendered according to the type of builtin function being used.
+ data, builtin = instr.constant_data.data_and_builtin
+ if builtin in [BuiltinType.BuiltinStrcpy, BuiltinType.BuiltinStrncpy]:
+ data = data.escape(null_terminates=True)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, f'"{data}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstStringDataTokenContext))
+ elif builtin == BuiltinType.BuiltinMemset:
+ tokens.append_open_brace()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken,
+ f"{instr.constant_data.value:#x}",
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstDataTokenContext))
+ tokens.append_close_brace()
+ else:
+ string, string_type = self.function.view.stringify_unicode_data(self.function.arch, data)
+ if string is not None:
+ wide_string_prefix = ""
+ token_context = InstructionTextTokenContext.ConstDataTokenContext
+ if builtin == BuiltinType.BuiltinWcscpy:
+ wide_string_prefix = "L"
+ token_context = InstructionTextTokenContext.ConstStringDataTokenContext
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken,
+ f'{wide_string_prefix}"{string}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=token_context))
+ else:
+ data = data.escape(null_terminates=False, escape_printable=True)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, f'"{data}"',
+ address=instr.address, value=instr.constant_data.value,
+ context=InstructionTextTokenContext.ConstDataTokenContext))
+ elif instr.operation == HighLevelILOperation.HLIL_EXTERN_PTR:
+ # Extern pointer instructions have an offset associated with them. If this is nonzero, show this
+ # as an addition or subtraction of the offset.
+ parens = instr.offset != 0 and precedence >= OperatorPrecedence.AddOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.offset != 0:
+ precedence = OperatorPrecedence.SubOperatorPrecedence
+ tokens.append_pointer_text_token(instr, instr.constant, settings,
+ SymbolDisplayType.AddressOfDataSymbols, precedence)
+ if instr.offset < 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " - "))
+ tokens.append_integer_text_token(instr, -instr.offset, instr.size)
+ elif instr.offset > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " + "))
+ tokens.append_integer_text_token(instr, instr.offset, instr.size)
+
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_VAR:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.LocalVariableToken, instr.var.name,
+ address=instr.expr_index, size=instr.size,
+ value=instr.var.identifier,
+ context=InstructionTextTokenContext.LocalVariableTokenContext))
+ elif instr.operation == HighLevelILOperation.HLIL_ASSIGN:
+ # Check to see if the variable appears live
+ appears_dead = False
+ if instr.dest.operation == HighLevelILOperation.HLIL_VAR:
+ ssa = instr.ssa_form
+ if ssa is not None and ssa.operation == HighLevelILOperation.HLIL_VAR_INIT_SSA:
+ appears_dead = not self.hlil.is_ssa_var_live(ssa.dest)
+
+ # If the variable does not appear live, show the assignment as zero confidence (grayed out)
+ with tokens.force_zero_confidence(appears_dead):
+ self.perform_get_expr_text(instr.dest, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+
+ # For the right side of the assignment, only use zero confidence if the instruction does
+ # not have any side effects
+ with tokens.force_zero_confidence(appears_dead and not instr.src.has_side_effects):
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_ASSIGN_UNPACK:
+ tokens.append_open_paren()
+ for (i, dest) in enumerate(instr.dest):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(dest, tokens, settings)
+ tokens.append_close_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " = "))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.AssignmentOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_STRUCT_FIELD:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ self.append_field_text_tokens(instr.src, instr.offset, instr.member_index, instr.size, tokens)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_DEREF_FIELD:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.src.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ tokens.append_pointer_text_token(instr.src, instr.src.constant, settings,
+ SymbolDisplayType.DisplaySymbolOnly,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ else:
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.MemberAndFunctionOperatorPrecedence)
+ self.append_field_text_tokens(instr.src, instr.offset, instr.member_index, instr.size, tokens)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_DEREF:
+ if instr.src.operation == HighLevelILOperation.HLIL_CONST_PTR:
+ if tokens.append_pointer_text_token(instr.src, instr.src.constant, settings,
+ SymbolDisplayType.DereferenceNonDataSymbols,
+ precedence) == SymbolDisplayResult.DataSymbolResult:
+ expr_type = instr.src.expr_type
+ if isinstance(expr_type, PointerType) and expr_type.target.width != instr.size:
+ # If dereference size doesn't match the data variable size, append a size suffix
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if instr.size in suffix:
+ suffix_str = suffix[instr.size]
+ else:
+ suffix_str = f".{instr.size}"
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, suffix_str))
+ else:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "*"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADDRESS_OF:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "&"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_E, HighLevelILOperation.HLIL_FCMP_E]:
+ parens = precedence > OperatorPrecedence.EqualityOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " == "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_NE, HighLevelILOperation.HLIL_FCMP_NE]:
+ parens = precedence > OperatorPrecedence.EqualityOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " != "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.EqualityOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SLT, HighLevelILOperation.HLIL_CMP_ULT,
+ HighLevelILOperation.HLIL_FCMP_LT]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " < "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SLE, HighLevelILOperation.HLIL_CMP_ULE,
+ HighLevelILOperation.HLIL_FCMP_LE]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " <= "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SGE, HighLevelILOperation.HLIL_CMP_UGE,
+ HighLevelILOperation.HLIL_FCMP_GE]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " >= "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_CMP_SGT, HighLevelILOperation.HLIL_CMP_UGT,
+ HighLevelILOperation.HLIL_FCMP_GT]:
+ parens = precedence > OperatorPrecedence.CompareOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, " > "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast,
+ OperatorPrecedence.CompareOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_AND:
+ if instr.size == 0:
+ # Size of zero is a boolean operation, show the boolean operator name
+ parens = (precedence >= OperatorPrecedence.BitwiseOrOperatorPrecedence or
+ precedence == OperatorPrecedence.LogicalOrOperatorPrecedence)
+ operation = "and"
+ precedence = OperatorPrecedence.LogicalAndOperatorPrecedence
+ else:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ operation = "&"
+ precedence = OperatorPrecedence.BitwiseAndOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(operation, instr, tokens, settings, as_full_ast, precedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_OR:
+ if instr.size == 0:
+ # Size of zero is a boolean operation, show the boolean operator name
+ parens = (precedence >= OperatorPrecedence.BitwiseOrOperatorPrecedence or
+ precedence == OperatorPrecedence.LogicalAndOperatorPrecedence)
+ operation = "or"
+ precedence = OperatorPrecedence.LogicalOrOperatorPrecedence
+ else:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ operation = "|"
+ precedence = OperatorPrecedence.BitwiseOrOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(operation, instr, tokens, settings, as_full_ast, precedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_XOR:
+ parens = (precedence >= OperatorPrecedence.EqualityOperatorPrecedence or
+ precedence in [OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("^", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "adc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SBB:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "sbb"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ADD_OVERFLOW:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "add_overflow"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_ADD, HighLevelILOperation.HLIL_FADD]:
+ parens = (precedence > OperatorPrecedence.AddOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("+", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.AddOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_SUB, HighLevelILOperation.HLIL_FSUB]:
+ parens = (precedence > OperatorPrecedence.AddOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("-", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.SubOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_MUL, HighLevelILOperation.HLIL_MULS_DP,
+ HighLevelILOperation.HLIL_MULU_DP, HighLevelILOperation.HLIL_FMUL]:
+ parens = (precedence > OperatorPrecedence.MultiplyOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("*", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.MultiplyOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_DIVS, HighLevelILOperation.HLIL_DIVU,
+ HighLevelILOperation.HLIL_DIVS_DP, HighLevelILOperation.HLIL_DIVU_DP]:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("//", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_MODS, HighLevelILOperation.HLIL_MODU,
+ HighLevelILOperation.HLIL_MODS_DP, HighLevelILOperation.HLIL_MODU_DP]:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("%", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FDIV:
+ parens = (precedence > OperatorPrecedence.DivideOperatorPrecedence or
+ precedence in [OperatorPrecedence.ShiftOperatorPrecedence,
+ OperatorPrecedence.BitwiseAndOperatorPrecedence,
+ OperatorPrecedence.BitwiseOrOperatorPrecedence,
+ OperatorPrecedence.BitwiseXorOperatorPrecedence])
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("/", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.DivideOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_LSL:
+ parens = precedence > OperatorPrecedence.ShiftOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens("<<", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.ShiftOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_LSR, HighLevelILOperation.HLIL_ASR]:
+ parens = precedence > OperatorPrecedence.ShiftOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.append_two_operand_tokens(">>", instr, tokens, settings, as_full_ast,
+ OperatorPrecedence.ShiftOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROL:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rol"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROR:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "ror"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RLC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rlc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RRC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "rrc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.carry, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_TEST_BIT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "test_bit"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FLOOR:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "floor"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_CEIL:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "ceil"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FTRUNC:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "trunc"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FABS:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fabs"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FSQRT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "sqrt"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_ROUND_TO_INT:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "round"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FCMP_O:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fcmp_o"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_FCMP_UO:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "fcmp_uo"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.left, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.right, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_NOT:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ if instr.size == 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "not "))
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "~"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_NEG, HighLevelILOperation.HLIL_FNEG]:
+ parens = precedence > OperatorPrecedence.UnaryOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "-"))
+ self.perform_get_expr_text(instr.src, tokens, settings, as_full_ast,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_FLOAT_CONV, HighLevelILOperation.HLIL_INT_TO_FLOAT]:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "float"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_FLOAT_TO_INT, HighLevelILOperation.HLIL_BOOL_TO_INT]:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "int"))
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ tokens.append_close_paren()
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_RET:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "return"))
+ operands = instr.src
+ if len(operands) > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " "))
+ if len(operands) > 1:
+ tokens.append_open_paren()
+ for (i, operand) in enumerate(operands):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(operand, tokens, settings)
+ if len(operands) > 1:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_NORET:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# no return"))
+ elif instr.operation == HighLevelILOperation.HLIL_UNREACHABLE:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# unreachable"))
+ elif instr.operation == HighLevelILOperation.HLIL_UNDEF:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# undefined"))
+ elif instr.operation == HighLevelILOperation.HLIL_NOP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# nop"))
+ elif instr.operation == HighLevelILOperation.HLIL_BP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "breakpoint"))
+ tokens.append_open_paren()
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_JUMP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# jump -> "))
+ self.perform_get_expr_text(instr.dest, tokens, settings)
+ elif instr.operation == HighLevelILOperation.HLIL_TRAP:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "trap"))
+ tokens.append_open_paren()
+ tokens.append_integer_text_token(instr, instr.vector, 8)
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_GOTO:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "goto "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.GotoLabelToken, instr.target.name,
+ instr.target.label_id))
+ elif instr.operation == HighLevelILOperation.HLIL_LABEL:
+ tokens.decrease_indent()
+ tokens.append(InstructionTextToken(InstructionTextTokenType.GotoLabelToken, instr.target.name,
+ instr.target.label_id))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ tokens.increase_indent()
+ elif instr.operation == HighLevelILOperation.HLIL_LOW_PART:
+ parens = precedence > OperatorPrecedence.MemberAndFunctionOperatorPrecedence
+ if parens:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.src, tokens, settings)
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if instr.size in suffix:
+ suffix_str = suffix[instr.size]
+ else:
+ suffix_str = f".{instr.size}"
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StructOffsetToken, suffix_str, value=0,
+ size=instr.size))
+ if parens:
+ tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_SPLIT:
+ tokens.append_open_paren()
+ self.perform_get_expr_text(instr.high, tokens, settings)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ self.perform_get_expr_text(instr.low, tokens, settings)
+ tokens.append_close_paren()
+ elif instr.operation in [HighLevelILOperation.HLIL_UNIMPL, HighLevelILOperation.HLIL_UNIMPL_MEM]:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken, "# "))
+ for token in instr.tokens:
+ token.token_type = InstructionTextTokenType.AnnotationToken
+ tokens.append(token)
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.AnnotationToken,
+ f"# unimplemented {instr.operation.name}"))
+
+ def append_two_operand_tokens(self, operation: str, instr: HighLevelILInstruction, tokens: HighLevelILTokenEmitter,
+ settings: Optional[DisassemblySettings], as_full_ast: bool,
+ precedence: OperatorPrecedence):
+ if precedence == OperatorPrecedence.SubOperatorPrecedence:
+ # Treat left side of subtraction as same level as addition. This lets
+ # (a - b) - c be represented as a - b - c, but a - (b - c) does not
+ # simplify at rendering
+ left_precedence = OperatorPrecedence.AddOperatorPrecedence
+ elif precedence == OperatorPrecedence.DivideOperatorPrecedence:
+ # Treat left side of divison as same level as multiplication. This lets
+ # (a / b) / c be represented as a / b / c, but a / (b / c) does not
+ # simplify at rendering
+ left_precedence = OperatorPrecedence.MultiplyOperatorPrecedence
+ else:
+ left_precedence = precedence
+
+ self.perform_get_expr_text(instr.left, tokens, settings, as_full_ast, left_precedence)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, f" {operation} "))
+ self.perform_get_expr_text(instr.right, tokens, settings, as_full_ast, precedence)
+
+ def append_field_text_tokens(self, var: HighLevelILInstruction, offset: int, member_index: int, size: int,
+ tokens: HighLevelILTokenEmitter):
+ var_type = var.expr_type
+ # Follow pointer type to its target
+ if isinstance(var_type, PointerType):
+ var_type = var_type.target
+ # Follow named type references to the target
+ if isinstance(var_type, NamedTypeReferenceType):
+ target_type = var_type.target(var.function.view)
+ if target_type is not None:
+ var_type = target_type
+
+ has_field = False
+ if isinstance(var_type, StructureType):
+ # For structures, resolve field names using the type API
+ class Resolver:
+ def __init__(self, view: BinaryView, offset: int):
+ self.has_field = False
+ self.correct_size = False
+ self.offset = offset
+ self.view = view
+
+ def resolve_func(self, base_name: Optional[NamedTypeReferenceType],
+ resolved_struct: Optional[StructureType], resolved_member_index: int,
+ struct_offset: int, adjusted_offset: int, member: StructureMember):
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "."))
+ name_list = HighLevelILTokenEmitter.names_for_outer_structure_members(
+ self.view, var_type, var) + [member.name]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FieldNameToken, member.name,
+ value=struct_offset + member.offset, typeNames=name_list))
+ self.offset = adjusted_offset - member.offset
+ self.has_field = True
+ self.correct_size = member.type is not None and size == member.type.width
+
+ resolver = Resolver(self.function.view, offset)
+ result = var_type.resolve_member_or_base_member(resolver.view, offset, 0, resolver.resolve_func)
+ if result and resolver.has_field and resolver.correct_size:
+ # If the field was matched, we're done
+ return
+ has_field = resolver.has_field
+ offset = resolver.offset
+
+ # Generate offset syntax for the missing field
+ suffix = {0: "", 1: ".b", 2: ".w", 4: ".d", 8: ".q", 10: ".t", 16: ".q"}
+ if size in suffix:
+ suffix_str = suffix[size]
+ else:
+ suffix_str = f".{size}"
+ if (has_field or not isinstance(var_type, StructureType)) and offset == 0:
+ # No offset, just display a size suffix
+ offset_str = suffix_str
+ else:
+ # Has an offset
+ offset_str = f".__offset({offset:#x}){suffix_str}"
+
+ name_list = HighLevelILTokenEmitter.names_for_outer_structure_members(
+ self.function.view, var_type, var) + [offset_str]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.StructOffsetToken, offset_str, value=offset,
+ size=size, typeNames=name_list))
+
+
+class PseudoPythonFunctionType(LanguageRepresentationFunctionType):
+ language_name = "Pseudo Python"
+
+ def create(self, arch: Architecture, owner: Function, hlil: HighLevelILFunction):
+ return PseudoPythonFunction(arch, owner, hlil)
+
+ def function_type_tokens(self, func: Function, settings: DisassemblySettings) -> DisassemblyTextLine:
+ tokens = []
+ tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "def "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "("))
+ for (i, param) in enumerate(func.type.parameters_with_all_locations):
+ if i > 0:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.ArgumentNameToken, param.name,
+ context=InstructionTextTokenContext.LocalVariableTokenContext,
+ address=param.location.identifier))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
+ for token in param.type.get_tokens():
+ token.context = InstructionTextTokenContext.LocalVariableTokenContext
+ token.address = param.location.identifier
+ tokens.append(token)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, ")"))
+ if func.can_return.value and func.type.return_value is not None and not isinstance(func.type.return_value, VoidType):
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " -> "))
+ for token in func.type.return_value.get_tokens():
+ token.context = InstructionTextTokenContext.FunctionReturnTokenContext
+ tokens.append(token)
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
+ return [DisassemblyTextLine(tokens, func.start)]
+
+
+PseudoPythonFunctionType().register()
diff --git a/python/function.py b/python/function.py
index 5ed61603..c8acf287 100644
--- a/python/function.py
+++ b/python/function.py
@@ -27,8 +27,9 @@ from dataclasses import dataclass
# Binary Ninja components
from . import _binaryninjacore as core
from .enums import (
- AnalysisSkipReason, FunctionGraphType, SymbolType, InstructionTextTokenType, HighlightStandardColor,
- HighlightColorStyle, DisassemblyOption, IntegerDisplayType, FunctionAnalysisSkipOverride, FunctionUpdateType
+ AnalysisSkipReason, FunctionGraphType, SymbolType, InstructionTextTokenType, HighlightStandardColor,
+ HighlightColorStyle, DisassemblyOption, IntegerDisplayType, FunctionAnalysisSkipOverride, FunctionUpdateType,
+ BuiltinType
)
from .exceptions import ILException
@@ -45,6 +46,7 @@ from . import variable
from . import flowgraph
from . import callingconvention
from . import workflow
+from . import languagerepresentation
from . import deprecation
from . import __version__
@@ -76,6 +78,7 @@ ILFunctionType = Union['lowlevelil.LowLevelILFunction', 'mediumlevelil.MediumLev
ILInstructionType = Union['lowlevelil.LowLevelILInstruction', 'mediumlevelil.MediumLevelILInstruction',
'highlevelil.HighLevelILInstruction']
StringOrType = Union[str, 'types.Type', 'types.TypeBuilder']
+FunctionViewTypeOrName = Union['FunctionViewType', FunctionGraphType, str]
def _function_name_():
@@ -181,6 +184,39 @@ class VariableReferenceSource:
return f"<var: {repr(self.var)}, src: {repr(self.src)}>"
+@dataclass
+class FunctionViewType:
+ view_type: FunctionGraphType
+ name: Optional[str]
+
+ def __init__(self, view_type: FunctionViewTypeOrName):
+ if isinstance(view_type, FunctionViewType):
+ self.view_type = view_type.view_type
+ self.name = view_type.name
+ if isinstance(view_type, FunctionGraphType):
+ self.view_type = view_type
+ self.name = None
+ else:
+ self.view_type = FunctionGraphType.HighLevelLanguageRepresentationFunctionGraph
+ self.name = str(view_type)
+
+ @staticmethod
+ def _from_core_struct(view_type: core.BNFunctionViewType) -> 'FunctionViewType':
+ if view_type.type == FunctionGraphType.HighLevelLanguageRepresentationFunctionGraph:
+ if view_type.name is None:
+ return FunctionViewType("Pseudo C")
+ else:
+ return FunctionViewType(view_type.name)
+ else:
+ return FunctionViewType(view_type.type)
+
+ def _to_core_struct(self) -> core.BNFunctionViewType:
+ result = core.BNFunctionViewType()
+ result.type = self.view_type
+ result.name = self.name
+ return result
+
+
class BasicBlockList:
def __init__(
self, function: Union['Function', 'lowlevelil.LowLevelILFunction', 'mediumlevelil.MediumLevelILFunction',
@@ -1069,6 +1105,30 @@ class Function:
return highlevelil.HighLevelILFunction(self.arch, result, self)
@property
+ def pseudo_c(self) -> Optional['languagerepresentation.LanguageRepresentationFunction']:
+ return self.language_representation("Pseudo C")
+
+ @property
+ def pseudo_c_if_available(self) -> Optional['languagerepresentation.LanguageRepresentationFunction']:
+ return self.language_representation_if_available("Pseudo C")
+
+ def language_representation(
+ self, language: str
+ ) -> Optional['languagerepresentation.LanguageRepresentationFunction']:
+ result = core.BNGetFunctionLanguageRepresentation(self.handle, language)
+ if result is None:
+ return None
+ return languagerepresentation.LanguageRepresentationFunction(handle=result)
+
+ def language_representation_if_available(
+ self, language: str
+ ) -> Optional['languagerepresentation.LanguageRepresentationFunction']:
+ result = core.BNGetFunctionLanguageRepresentationIfAvailable(self.handle, language)
+ if result is None:
+ return None
+ return languagerepresentation.LanguageRepresentationFunction(handle=result)
+
+ @property
def type(self) -> 'types.FunctionType':
"""
Function type object, can be set with either a string representing the function prototype
@@ -1787,7 +1847,15 @@ class Function:
core.BNFreeILInstructionList(exits)
def get_constant_data(self, state: RegisterValueType, value: int, size: int = 0) -> databuffer.DataBuffer:
- return databuffer.DataBuffer(handle=core.BNGetConstantData(self.handle, state, value, size))
+ return databuffer.DataBuffer(handle=core.BNGetConstantData(self.handle, state, value, size, None))
+
+ def get_constant_data_and_builtin(
+ self, state: RegisterValueType, value: int, size: int = 0
+ ) -> Tuple[databuffer.DataBuffer, BuiltinType]:
+ builtin = ctypes.c_int()
+ db = databuffer.DataBuffer(
+ handle=core.BNGetConstantData(self.handle, state, value, size, ctypes.byref(builtin)))
+ return db, BuiltinType(builtin.value)
def get_reg_value_at(
self, addr: int, reg: 'architecture.RegisterType', arch: Optional['architecture.Architecture'] = None
@@ -2078,13 +2146,14 @@ class Function:
return result
def create_graph(
- self, graph_type: FunctionGraphType = FunctionGraphType.NormalFunctionGraph,
+ self, graph_type: FunctionViewTypeOrName = FunctionGraphType.NormalFunctionGraph,
settings: Optional['DisassemblySettings'] = None
) -> flowgraph.CoreFlowGraph:
if settings is not None:
settings_obj = settings.handle
else:
settings_obj = None
+ graph_type = FunctionViewType(graph_type)._to_core_struct()
return flowgraph.CoreFlowGraph(core.BNCreateFunctionGraph(self.handle, graph_type, settings_obj))
def apply_imported_types(self, sym: 'types.CoreSymbol', type: Optional[StringOrType] = None) -> None:
diff --git a/python/highlevelil.py b/python/highlevelil.py
index 48cbd6cc..21359685 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -907,6 +907,10 @@ class HighLevelILInstruction(BaseILInstruction):
return False
return True
+ @property
+ def has_side_effects(self) -> bool:
+ return core.BNHighLevelILHasSideEffects(self.function.handle, self.expr_index)
+
@dataclass(frozen=True, repr=False, eq=False)
class HighLevelILUnaryBase(HighLevelILInstruction, UnaryOperation):
diff --git a/python/languagerepresentation.py b/python/languagerepresentation.py
new file mode 100644
index 00000000..49a300c1
--- /dev/null
+++ b/python/languagerepresentation.py
@@ -0,0 +1,822 @@
+# Copyright (c) 2024 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import ctypes
+import traceback
+from typing import List, Optional, Union
+
+# Binary Ninja components
+import binaryninja
+from . import _binaryninjacore as core
+from . import architecture
+from . import binaryview
+from . import function
+from . import highlevelil
+from . import highlight
+from . import variable
+from . import types
+from .log import log_error
+from .enums import BraceRequirement, HighlightStandardColor, InstructionTextTokenType, OperatorPrecedence, ScopeType, \
+ SymbolDisplayType, SymbolDisplayResult
+
+
+class HighLevelILTokenEmitter:
+ """
+ ``class HighLevelILTokenEmitter`` contains methods for emitting text tokens for High Level IL instructions.
+ Methods are provided for typical patterns found in various high level languages.
+
+ This class cannot be instantiated directly. An instance of the class will be provided when the methods
+ in ``class LanguageRepresentationFunction`` are called.
+ """
+ def __init__(self, handle: core.BNHighLevelILTokenEmitterHandle):
+ self.handle = handle
+
+ def __del__(self):
+ if core is not None:
+ core.BNFreeHighLevelILTokenEmitter(self.handle)
+
+ def new_line(self):
+ """Starts a new line in the output."""
+ core.BNHighLevelILTokenEmitterNewLine(self.handle)
+
+ def increase_indent(self):
+ """Increases the indentation level by one."""
+ core.BNHighLevelILTokenEmitterIncreaseIndent(self.handle)
+
+ def decrease_indent(self):
+ """Decreases the indentation level by one."""
+ core.BNHighLevelILTokenEmitterDecreaseIndent(self.handle)
+
+ def scope_separator(self):
+ """
+ Indicates that visual separation of scopes is desirable at the current position. By default,
+ this will insert a blank line, but this can be configured by the user.
+ """
+ core.BNHighLevelILTokenEmitterScopeSeparator(self.handle)
+
+ def begin_scope(self, scope_type: ScopeType):
+ """Begins a new scope. Insertion of newlines and braces will be handled using the current settings."""
+ core.BNHighLevelILTokenEmitterBeginScope(self.handle, scope_type)
+
+ def end_scope(self, scope_type: ScopeType):
+ """Ends the current scope."""
+ core.BNHighLevelILTokenEmitterEndScope(self.handle, scope_type)
+
+ def scope_continuation(self, force_same_line: bool):
+ """Continues the previous scope with a new associated scope. This is most commonly used for ``else`` statements."""
+ core.BNHighLevelILTokenEmitterScopeContinuation(self.handle, force_same_line)
+
+ def finalize_scope(self):
+ """Finalizes the previous scope, indicating that there are no more associated scopes."""
+ core.BNHighLevelILTokenEmitterFinalizeScope(self.handle)
+
+ def no_indent_for_this_line(self):
+ """Forces there to be no indentation for the next line."""
+ core.BNHighLevelILTokenEmitterNoIndentForThisLine(self.handle)
+
+ class ZeroConfidenceContext:
+ """
+ ``class ZeroConfidenceContext`` is a context manager that optionally forces tokens to be of zero confidence
+ inside the context.
+ """
+ def __init__(self, emitter: 'HighLevelILTokenEmitter', enabled: bool):
+ self.emitter = emitter
+ self.enabled = enabled
+
+ def __enter__(self):
+ if self.enabled:
+ core.BNHighLevelILTokenEmitterBeginForceZeroConfidence(self.emitter.handle)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if self.enabled:
+ core.BNHighLevelILTokenEmitterEndForceZeroConfidence(self.emitter.handle)
+
+ def force_zero_confidence(self, enabled: bool = True) -> 'HighLevelILTokenEmitter.ZeroConfidenceContext':
+ """
+ Returns a context manager that forces tokens inside of it to be of zero confidence. If ``False`` is passed
+ to this method, the context has no effect, allowing the caller to conditionally apply this behavior.
+ """
+ return HighLevelILTokenEmitter.ZeroConfidenceContext(self, enabled)
+
+ class ExprContext:
+ """
+ ``class ExprContext`` is a context manager that associates the tokens inside the context with the given
+ High Level IL expression.
+ """
+ def __init__(self, emitter: 'HighLevelILTokenEmitter', hlil_expr: highlevelil.HighLevelILInstruction):
+ self.emitter = emitter
+ self.expr = hlil_expr
+ self.prev_expr = None
+
+ def __enter__(self):
+ expr = core.BNTokenEmitterExpr()
+ expr.address = self.expr.address
+ expr.sourceOperand = self.expr.source_operand
+ expr.exprIndex = self.expr.expr_index
+ expr.instrIndex = self.expr.instr_index
+ self.prev_expr = core.BNHighLevelILTokenEmitterSetCurrentExpr(self.emitter.handle, expr)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if self.prev_expr is not None:
+ core.BNHighLevelILTokenEmitterRestoreCurrentExpr(self.emitter.handle, self.prev_expr)
+
+ def expr(self, hlil_expr: 'highlevelil.HighLevelILInstruction') -> 'HighLevelILTokenEmitter.ExprContext':
+ """
+ Returns a context manager that associates the tokens inside the context with the given High Level IL expression.
+ """
+ return HighLevelILTokenEmitter.ExprContext(self, hlil_expr)
+
+ def finalize(self):
+ """Finalizes all tokens in the output."""
+ core.BNHighLevelILTokenEmitterFinalize(self.handle)
+
+ def append(self, tokens: Union['architecture.InstructionTextToken', List['architecture.InstructionTextToken']]):
+ """Appends a token or list of tokens to the output."""
+ if not isinstance(tokens, list):
+ tokens = [tokens]
+ buf = architecture.InstructionTextToken._get_core_struct(tokens)
+ for i in range(len(tokens)):
+ core.BNHighLevelILTokenEmitterAppend(self.handle, buf[i])
+
+ def append_open_paren(self):
+ """Appends an open parenthesis (``(``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendOpenParen(self.handle)
+
+ def append_close_paren(self):
+ """Appends a close parenthesis (``)``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendCloseParen(self.handle)
+
+ def append_open_bracket(self):
+ """Appends an open bracket (``[``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendOpenBracket(self.handle)
+
+ def append_close_bracket(self):
+ """Appends a close bracket (``]``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendCloseBracket(self.handle)
+
+ def append_open_brace(self):
+ """Appends an open brace (``{``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendOpenBrace(self.handle)
+
+ def append_close_brace(self):
+ """Appends a close brace (``}``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendCloseBrace(self.handle)
+
+ def append_semicolon(self):
+ """Appends a semicolon (``;``) to the output."""
+ core.BNHighLevelILTokenEmitterAppendSemicolon(self.handle)
+
+ @property
+ def current_tokens(self) -> List['function.InstructionTextToken']:
+ """The list of tokens on the current line (read-only)."""
+ count = ctypes.c_ulonglong()
+ tokens = core.BNHighLevelILTokenEmitterGetCurrentTokens(self.handle, count)
+ result = []
+ if tokens is not None:
+ result = function.InstructionTextToken._from_core_struct(tokens, count.value)
+ core.BNFreeInstructionText(tokens, count.value)
+ return result
+
+ @property
+ def lines(self) -> List['function.DisassemblyTextLine']:
+ """The list of lines in the output (read-only)."""
+ count = ctypes.c_ulonglong()
+ lines = core.BNHighLevelILTokenEmitterGetLines(self.handle, count)
+ result = []
+ if lines is not None:
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ result.append(function.DisassemblyTextLine(tokens, addr, color=color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
+
+ @property
+ def brace_requirement(self) -> BraceRequirement:
+ """The requirement for insertion of braces around scopes in the output."""
+ return core.BNHighLevelILTokenEmitterGetBraceRequirement(self.handle)
+
+ @brace_requirement.setter
+ def brace_requirement(self, value: BraceRequirement):
+ core.BNHighLevelILTokenEmitterSetBraceRequirement(self.handle, value)
+
+ @property
+ def braces_around_switch_cases(self):
+ """Whether cases within switch statements should always have braces around them."""
+ return core.BNHighLevelILTokenEmitterHasBracesAroundSwitchCases(self.handle)
+
+ @braces_around_switch_cases.setter
+ def braces_around_switch_cases(self, value: bool):
+ core.BNHighLevelILTokenEmitterSetBracesAroundSwitchCases(self.handle, value)
+
+ @property
+ def default_braces_on_same_line(self):
+ """
+ Whether braces should default to being on the same line as the statement that begins the scope.
+ If the user has explicitly set a preference, this setting will be ignored and the user's preference
+ will be used instead.
+ """
+ return core.BNHighLevelILTokenEmitterGetDefaultBracesOnSameLine(self.handle)
+
+ @default_braces_on_same_line.setter
+ def default_braces_on_same_line(self, value: bool):
+ core.BNHighLevelILTokenEmitterSetDefaultBracesOnSameLine(self.handle, value)
+
+ @property
+ def simple_scope_allowed(self):
+ """Whether omitting braces around single-line scopes is allowed."""
+ return core.BNHighLevelILTokenEmitterIsSimpleScopeAllowed(self.handle)
+
+ @simple_scope_allowed.setter
+ def simple_scope_allowed(self, value: bool):
+ core.BNHighLevelILTokenEmitterSetSimpleScopeAllowed(self.handle, value)
+
+ def append_size_token(self, size: int, token_type: InstructionTextTokenType):
+ """Appends a size token for the given size in the High Level IL syntax."""
+ core.BNAddHighLevelILSizeToken(size, token_type, self.handle)
+
+ def append_float_size_token(self, size: int, token_type: InstructionTextTokenType):
+ """Appends a floating point size token for the given size in the High Level IL syntax."""
+ core.BNAddHighLevelILFloatSizeToken(size, token_type, self.handle)
+
+ def append_var_text_token(
+ self, var: 'variable.CoreVariable', instr: 'highlevelil.HighLevelILInstruction',
+ size: int
+ ):
+ """Appends tokens for access to a variable."""
+ core.BNAddHighLevelILVarTextToken(
+ instr.function.handle, var.to_BNVariable(), self.handle, instr.expr_index, size)
+
+ def append_integer_text_token(self, instr: 'highlevelil.HighLevelILInstruction', value: int, size: int):
+ """Appends tokens for a constant intenger value."""
+ core.BNAddHighLevelILIntegerTextToken(instr.function.handle, instr.expr_index, value, size, self.handle)
+
+ def append_array_index_token(
+ self, instr: 'highlevelil.HighLevelILInstruction', value: int, size: int, address: int = 0):
+ """Appends tokens for accessing an array by index."""
+ core.BNAddHighLevelILArrayIndexToken(instr.function.handle, instr.expr_index, value, size, self.handle, address)
+
+ def append_pointer_text_token(
+ self, instr: 'highlevelil.HighLevelILInstruction', value: int,
+ settings: Optional['function.DisassemblySettings'], symbol_display: SymbolDisplayType,
+ precedence: OperatorPrecedence, allow_short_string: bool = False
+ ) -> SymbolDisplayResult:
+ """Appends tokens for displaying a constant pointer value."""
+ if settings is not None:
+ settings = settings.handle
+ return SymbolDisplayResult(core.BNAddHighLevelILPointerTextToken(
+ instr.function.handle, instr.expr_index, value, self.handle, settings, symbol_display, precedence,
+ allow_short_string))
+
+ def append_constant_text_token(
+ self, instr: 'highlevelil.HighLevelILInstruction', value: int, size: int,
+ settings: Optional['function.DisassemblySettings'], precedence: OperatorPrecedence
+ ):
+ """Appends tokens for a constant value."""
+ if settings is not None:
+ settings = settings.handle
+ core.BNAddHighLevelILConstantTextToken(
+ instr.function.handle, instr.expr_index, value, size, self.handle, settings, precedence)
+
+ @staticmethod
+ def names_for_outer_structure_members(
+ view: 'binaryview.BinaryView', struct_type: 'types.Type', var: 'highlevelil.HighLevelILInstruction',
+ ) -> List[str]:
+ """
+ Gets the list of names for the outer structure members when accessing a structure member. This list
+ can be passed for the ``typeNames`` parameter of the ``class InstructionTextToken`` constructor.
+ """
+ count = ctypes.c_ulonglong()
+ result = core.BNAddNamesForOuterStructureMembers(
+ view.handle, struct_type.handle, var.function.handle, var.expr_index, count)
+ names = []
+ if result is not None:
+ for i in range(count.value):
+ names.append(result[i].decode("utf-8"))
+ core.BNFreeStringList(result, count.value)
+ return names
+
+
+class LanguageRepresentationFunction:
+ """
+ ``class LanguageRepresentationFunction`` represents a single function in a registered high level language.
+ """
+ _registered_instances = []
+ comment_start_string = "// "
+ comment_end_string = ""
+ annotation_start_string = "{"
+ annotation_end_string = "}"
+
+ def __init__(
+ self, arch: Optional['architecture.Architecture'] = None, owner: Optional['function.Function'] = None,
+ hlil: Optional['highlevelil.HighLevelILFunction'] = None, handle=None
+ ):
+ if handle is None:
+ if arch is None:
+ raise ValueError("function representation must have an associated architecture")
+ if owner is None:
+ raise ValueError("function representation must have an owning function")
+ if hlil is None:
+ raise ValueError("function representation must have an associated High Level IL function")
+ self._cb = core.BNCustomLanguageRepresentationFunction()
+ self._cb.context = 0
+ self._cb.externalRefTaken = self._cb.externalRefTaken.__class__(self._external_ref_taken)
+ self._cb.externalRefReleased = self._cb.externalRefReleased.__class__(self._external_ref_released)
+ self._cb.initTokenEmitter = self._cb.initTokenEmitter.__class__(self._init_token_emitter)
+ self._cb.getExprText = self._cb.getExprText.__class__(self._get_expr_text)
+ self._cb.beginLines = self._cb.beginLines.__class__(self._begin_lines)
+ self._cb.endLines = self._cb.endLines.__class__(self._end_lines)
+ self._cb.getCommentStartString = self._cb.getCommentStartString.__class__(self._comment_start_string)
+ self._cb.getCommentEndString = self._cb.getCommentEndString.__class__(self._comment_end_string)
+ self._cb.getAnnotationStartString = self._cb.getAnnotationStartString.__class__(
+ self._annotation_start_string)
+ self._cb.getAnnotationEndString = self._cb.getAnnotationEndString.__class__(self._annotation_end_string)
+ self.comment_start_string = self.__class__.comment_start_string
+ self.comment_end_string = self.__class__.comment_end_string
+ self.annotation_start_string = self.__class__.annotation_start_string
+ self.annotation_end_string = self.__class__.annotation_end_string
+ _handle = core.BNCreateCustomLanguageRepresentationFunction(arch.handle, owner.handle, hlil.handle, self._cb)
+ assert _handle is not None
+ else:
+ self.comment_start_string = core.BNGetLanguageRepresentationFunctionCommentStartString(handle)
+ self.comment_end_string = core.BNGetLanguageRepresentationFunctionCommentEndString(handle)
+ self.annotation_start_string = core.BNGetLanguageRepresentationFunctionAnnotationStartString(handle)
+ self.annotation_end_string = core.BNGetLanguageRepresentationFunctionAnnotationEndString(handle)
+ _handle = handle
+ assert _handle is not None
+ self.handle: core.BNLanguageRepresentationFunctionHandle = _handle
+
+ def __del__(self):
+ if core is not None:
+ core.BNFreeLanguageRepresentationFunction(self.handle)
+
+ def _external_ref_taken(self, ctxt):
+ try:
+ self.__class__._registered_instances.append(self)
+ except:
+ log_error(traceback.format_exc())
+
+ def _external_ref_released(self, ctxt):
+ try:
+ self.__class__._registered_instances.remove(self)
+ except:
+ log_error(traceback.format_exc())
+
+ def _init_token_emitter(self, ctxt, emitter: core.BNHighLevelILTokenEmitterHandle):
+ try:
+ emitter = HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(emitter))
+ self.perform_init_token_emitter(emitter)
+ except:
+ log_error(traceback.format_exc())
+
+ def _get_expr_text(
+ self, ctxt, hlil: core.BNHighLevelILFunctionHandle, expr_index: int,
+ tokens: core.BNHighLevelILTokenEmitterHandle, settings: Optional[core.BNDisassemblySettingsHandle],
+ as_full_ast: bool, precedence: OperatorPrecedence, statement: bool
+ ):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr_index))
+ tokens = HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(tokens))
+ if settings is not None:
+ settings = function.DisassemblySettings(core.BNNewDisassemblySettingsReference(settings))
+ self.perform_get_expr_text(instr, tokens, settings, as_full_ast, precedence, statement)
+ except:
+ log_error(traceback.format_exc())
+
+ def _begin_lines(
+ self, ctxt, hlil: core.BNHighLevelILFunctionHandle, expr_index: int,
+ tokens: core.BNHighLevelILTokenEmitterHandle
+ ):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr_index))
+ tokens = HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(tokens))
+ self.perform_begin_lines(instr, tokens)
+ except:
+ log_error(traceback.format_exc())
+
+ def _end_lines(
+ self, ctxt, hlil: core.BNHighLevelILFunctionHandle, expr_index: int,
+ tokens: core.BNHighLevelILTokenEmitterHandle
+ ):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr_index))
+ tokens = HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(tokens))
+ self.perform_end_lines(instr, tokens)
+ except:
+ log_error(traceback.format_exc())
+
+ def _comment_start_string(self, ctxt):
+ try:
+ return core.BNAllocString(self.comment_start_string)
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("// ")
+
+ def _comment_end_string(self, ctxt):
+ try:
+ return core.BNAllocString(self.comment_end_string)
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("")
+
+ def _annotation_start_string(self, ctxt):
+ try:
+ return core.BNAllocString(self.annotation_start_string)
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("{")
+
+ def _annotation_end_string(self, ctxt):
+ try:
+ return core.BNAllocString(self.annotation_end_string)
+ except:
+ log_error(traceback.format_exc())
+ return core.BNAllocString("}")
+
+ def perform_init_token_emitter(self, emitter: HighLevelILTokenEmitter):
+ """Override this method to initialize the options for the token emitter before it is used."""
+ pass
+
+ def perform_get_expr_text(
+ self, instr: 'highlevelil.HighLevelILInstruction', tokens: HighLevelILTokenEmitter,
+ settings: Optional['function.DisassemblySettings'], as_full_ast: bool = True,
+ precedence: OperatorPrecedence = OperatorPrecedence.TopLevelOperatorPrecedence, statement: bool = False
+ ):
+ """
+ This method must be overridden by all language representation plugins.
+
+ This method is called to emit the tokens for a given High Level IL instruction.
+ """
+ raise NotImplementedError
+
+ def perform_begin_lines(self, instr: highlevelil.HighLevelILInstruction, tokens: HighLevelILTokenEmitter):
+ """This method can be overridden to emit tokens at the start of a function."""
+ pass
+
+ def perform_end_lines(self, instr: highlevelil.HighLevelILInstruction, tokens: HighLevelILTokenEmitter):
+ """This method can be overridden to emit tokens at the end of a function."""
+ pass
+
+ def get_expr_text(
+ self, instr: 'highlevelil.HighLevelILInstruction', settings: Optional['function.DisassemblySettings'],
+ as_full_ast: bool = True, precedence: OperatorPrecedence = OperatorPrecedence.TopLevelOperatorPrecedence,
+ statement: bool = False
+ ) -> List['function.DisassemblyTextLine']:
+ """Gets the lines of tokens for a given High Level IL instruction."""
+ count = ctypes.c_ulonglong()
+ if settings is not None:
+ settings = settings.handle
+ lines = core.BNGetLanguageRepresentationFunctionExprText(self.handle, instr.function.handle, instr.expr_index,
+ settings, as_full_ast, precedence, statement, count)
+ result = []
+ if lines is not None:
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if lines[i].instrIndex != 0xffffffffffffffff:
+ il_instr = instr.function[lines[i].instrIndex] # type: ignore
+ else:
+ il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
+
+ def get_linear_lines(
+ self, instr: 'highlevelil.HighLevelILInstruction',
+ settings: Optional['function.DisassemblySettings'] = None,
+ as_full_ast: bool = True
+ ) -> List['function.DisassemblyTextLine']:
+ """
+ Generates lines for the given High Level IL instruction in the style of the linear view. To get the lines
+ for the entire function, pass the ``root`` property of a ``class HighLevelILFunction``.
+ """
+ count = ctypes.c_ulonglong()
+ if settings is not None:
+ settings = settings.handle
+ lines = core.BNGetLanguageRepresentationFunctionLinearLines(self.handle, instr.function.handle, instr.expr_index,
+ settings, as_full_ast, count)
+ result = []
+ if lines is not None:
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if lines[i].instrIndex != 0xffffffffffffffff:
+ il_instr = instr.function[lines[i].instrIndex] # type: ignore
+ else:
+ il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
+
+ def get_block_lines(
+ self, block: 'highlevelil.HighLevelILBasicBlock', settings: Optional['function.DisassemblySettings'] = None
+ ) -> List['function.DisassemblyTextLine']:
+ """Generates lines for a single High Level IL basic block."""
+ count = ctypes.c_ulonglong()
+ if settings is not None:
+ settings = settings.handle
+ lines = core.BNGetLanguageRepresentationFunctionBlockLines(self.handle, block.handle, settings, count)
+ result = []
+ if lines is not None:
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if lines[i].instrIndex != 0xffffffffffffffff:
+ il_instr = instr.function[lines[i].instrIndex] # type: ignore
+ else:
+ il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
+
+ @property
+ def arch(self) -> 'architecture.Architecture':
+ return architecture.CoreArchitecture._from_cache(core.BNGetLanguageRepresentationArchitecture(self.handle))
+
+ @property
+ def function(self) -> 'function.Function':
+ return function.Function(handle=core.BNGetLanguageRepresentationOwnerFunction(self.handle))
+
+ @property
+ def high_level_il(self) -> 'highlevelil.HighLevelILFunction':
+ return self.hlil
+
+ @property
+ def hlil(self) -> 'highlevelil.HighLevelILFunction':
+ return highlevelil.HighLevelILFunction(arch=self.arch,
+ handle=core.BNGetLanguageRepresentationILFunction(self.handle), source_func=self.function)
+
+
+class _LanguageRepresentationFunctionTypeMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ types = core.BNGetLanguageRepresentationFunctionTypeList(count)
+ assert types is not None, "core.BNGetLanguageRepresentationFunctionTypeList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CoreLanguageRepresentationFunctionType(handle=types[i])
+ finally:
+ core.BNFreeLanguageRepresentationFunctionTypeList(types)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ lang = core.BNGetLanguageRepresentationFunctionTypeByName(str(value))
+ if lang is None:
+ raise KeyError("'%s' is not a valid language" % str(value))
+ return CoreLanguageRepresentationFunctionType(handle=lang)
+
+
+class LanguageRepresentationFunctionType(metaclass=_LanguageRepresentationFunctionTypeMetaClass):
+ """
+ ``class LanguageRepresentationFunctionType`` represents a custom language representation function type.
+ This class provides methods to create ``class LanguageRepresentationFunction`` instances for functions, as well
+ as manage the printing and parsing of types.
+ """
+ _registered_languages = []
+ language_name = None
+
+ def __init__(self, handle=None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNLanguageRepresentationFunctionType)
+
+ def register(self):
+ """Registers the language representation function type."""
+ if self.__class__.language_name is None:
+ raise ValueError("Language name is missing")
+ self._cb = core.BNCustomLanguageRepresentationFunctionType()
+ self._cb.context = 0
+ self._cb.create = self._cb.create.__class__(self._create)
+ self._cb.isValid = self._cb.isValid.__class__(self._is_valid)
+ self._cb.getTypePrinter = self._cb.getTypePrinter.__class__(self._type_printer)
+ self._cb.getTypeParser = self._cb.getTypeParser.__class__(self._type_parser)
+ self._cb.getFunctionTypeTokens = self._cb.getFunctionTypeTokens.__class__(self._function_type_tokens)
+ self._cb.freeLines = self._cb.freeLines.__class__(self._free_lines)
+ self.handle = core.BNRegisterLanguageRepresentationFunctionType(self.__class__.language_name, self._cb)
+ self.__class__._registered_languages.append(self)
+
+ def _create(
+ self, ctxt, arch: core.BNArchitectureHandle, owner: core.BNFunctionHandle,
+ hlil: core.BNHighLevelILFunctionHandle
+ ):
+ try:
+ arch = architecture.CoreArchitecture._from_cache(arch)
+ owner = function.Function(handle=core.BNNewFunctionReference(owner))
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ result = self.create(arch, owner, hlil)
+ if result is None:
+ raise ValueError(f"create returned None for language representation '{self.name}'")
+ handle = core.BNNewLanguageRepresentationFunctionReference(result.handle)
+ assert handle is not None, "core.BNNewLanguageRepresentationFunctionReference returned None"
+ return ctypes.cast(handle, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ return None
+
+ def _is_valid(self, ctxt, view: core.BNBinaryViewHandle) -> bool:
+ try:
+ view = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ return self.is_valid(view)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def _type_printer(self, ctxt):
+ try:
+ result = self.type_printer
+ if result is None:
+ return None
+ return ctypes.cast(result.handle, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ return None
+
+ def _type_parser(self, ctxt):
+ try:
+ result = self.type_parser
+ if result is None:
+ return None
+ return ctypes.cast(result.handle, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ return None
+
+ def _function_type_tokens(
+ self, ctxt, func: core.BNFunctionHandle, settings: Optional[core.BNDisassemblySettingsHandle],
+ count: ctypes.POINTER(ctypes.c_ulonglong)
+ ):
+ try:
+ func = function.Function(handle=core.BNNewFunctionReference(func))
+ if settings is not None:
+ settings = function.DisassemblySettings(handle=core.BNNewDisassemblySettingsReference(settings))
+ lines = self.function_type_tokens(func, settings)
+
+ count[0] = len(lines)
+ self.line_buf = (core.BNDisassemblyTextLine * len(lines))()
+ for i in range(len(lines)):
+ line = lines[i]
+ color = line.highlight
+ 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)
+ self.line_buf[i].highlight = color._to_core_struct()
+ if line.address is None:
+ if len(line.tokens) > 0:
+ self.line_buf[i].addr = line.tokens[0].address
+ else:
+ self.line_buf[i].addr = 0
+ else:
+ self.line_buf[i].addr = line.address
+ if line.il_instruction is not None:
+ self.line_buf[i].instrIndex = line.il_instruction.instr_index
+ else:
+ self.line_buf[i].instrIndex = 0xffffffffffffffff
+
+ self.line_buf[i].count = len(line.tokens)
+ self.line_buf[i].tokens = function.InstructionTextToken._get_core_struct(line.tokens)
+
+ return ctypes.cast(self.line_buf, ctypes.c_void_p).value
+ except:
+ log_error(traceback.format_exc())
+ count[0] = 0
+ return None
+
+ def _free_lines(self, ctxt, lines, count):
+ self.line_buf = None
+
+ @property
+ def name(self) -> str:
+ if hasattr(self, 'handle'):
+ return core.BNGetLanguageRepresentationFunctionTypeName(self.handle)
+ return self.__class__.language_name
+
+ def create(
+ self, arch: 'architecture.Architecture', owner: 'function.Function', hlil: 'highlevelil.HighLevelILFunction'
+ ) -> LanguageRepresentationFunction:
+ """
+ This method must be overridden. This creates the ``class LanguageRepresentationFunction`` object for the
+ given architecture, owner function, and High Level IL function.
+ """
+ raise NotImplementedError
+
+ def is_valid(self, view: 'binaryview.BinaryView') -> bool:
+ """Returns whether the language is valid for the given binary view."""
+ return True
+
+ @property
+ def type_printer(self) -> Optional['binaryninja.typeprinter.TypePrinter']:
+ """
+ Returns the type printer for displaying types in this language. If ``None`` is returned, the default type
+ printer will be used.
+ """
+ return None
+
+ @property
+ def type_parser(self) -> Optional['binaryninja.typeparser.TypeParser']:
+ """
+ Returns the type parser for parsing types in this language. If ``None`` is returned, the default type
+ parser will be used.
+ """
+ return None
+
+ def function_type_tokens(
+ self, func: 'function.Function', settings: Optional['function.DisassemblySettings']
+ ) -> List['function.DisassemblyTextLine']:
+ """
+ Returns a list of lines representing a function prototype in this language. If no lines are returned, the
+ default C-style prototype will be used.
+ """
+ return []
+
+ def __repr__(self):
+ return f"<LanguageRepresentationFunctionType: {self.name}>"
+
+
+_language_cache = {}
+
+
+class CoreLanguageRepresentationFunctionType(LanguageRepresentationFunctionType):
+ def __init__(self, handle: core.BNLanguageRepresentationFunctionTypeHandle):
+ super(CoreLanguageRepresentationFunctionType, self).__init__(handle=handle)
+ if type(self) is CoreLanguageRepresentationFunctionType:
+ global _language_cache
+ _language_cache[ctypes.addressof(handle.contents)] = self
+
+ @classmethod
+ def _from_cache(cls, handle) -> 'LanguageRepresentationFunctionType':
+ """
+ Look up a representation type from a given BNLanguageRepresentationFunctionType handle
+ :param handle: BNLanguageRepresentationFunctionType pointer
+ :return: Respresentation type instance responsible for this handle
+ """
+ global _language_cache
+ return _language_cache.get(ctypes.addressof(handle.contents)) or cls(handle)
+
+ def create(
+ self, arch: 'architecture.Architecture', owner: 'function.Function', hlil: 'highlevelil.HighLevelILFunction'
+ ) -> LanguageRepresentationFunction:
+ raise NotImplementedError
+
+ def is_valid(self, view: 'binaryview.BinaryView') -> bool:
+ return core.BNIsLanguageRepresentationFunctionTypeValid(self.handle, view.handle)
+
+ @property
+ def type_printer(self) -> Optional['binaryninja.typeprinter.TypePrinter']:
+ result = core.BNGetLanguageRepresentationFunctionTypePrinter(self.handle)
+ if result is None:
+ return None
+ return binaryninja.typeprinter.TypePrinter(handle=result)
+
+ @property
+ def type_parser(self) -> Optional['binaryninja.typeparser.TypeParser']:
+ result = core.BNGetLanguageRepresentationFunctionTypeParser(self.handle)
+ if result is None:
+ return None
+ return binaryninja.typeparser.TypeParser(handle=result)
+
+ def function_type_tokens(
+ self, func: 'function.Function', settings: Optional['function.DisassemblySettings']
+ ) -> List['function.DisassemblyTextLine']:
+ count = ctypes.c_ulonglong()
+ if settings is not None:
+ settings = settings.handle
+ lines = core.BNGetLanguageRepresentationFunctionTypeFunctionTypeTokens(self.handle, func.handle, settings, count)
+ result = []
+ if lines is not None:
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ result.append(function.DisassemblyTextLine(tokens, addr, color=color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
diff --git a/python/lineardisassembly.py b/python/lineardisassembly.py
index a19148ca..40a0d6c5 100644
--- a/python/lineardisassembly.py
+++ b/python/lineardisassembly.py
@@ -345,12 +345,13 @@ class LinearViewObject:
@staticmethod
def language_representation(
- view: 'binaryview.BinaryView', settings: Optional['_function.DisassemblySettings'] = None
+ view: 'binaryview.BinaryView', settings: Optional['_function.DisassemblySettings'] = None,
+ language: str = "Pseudo C"
) -> 'LinearViewObject':
_settings = settings
if _settings is not None:
_settings = _settings.handle
- return LinearViewObject(core.BNCreateLinearViewLanguageRepresentation(view.handle, _settings))
+ return LinearViewObject(core.BNCreateLinearViewLanguageRepresentation(view.handle, _settings, language))
@staticmethod
def data_only(
@@ -453,12 +454,13 @@ class LinearViewObject:
@staticmethod
def single_function_language_representation(
- func: '_function.Function', settings: Optional['_function.DisassemblySettings'] = None
+ func: '_function.Function', settings: Optional['_function.DisassemblySettings'] = None,
+ language: str = "Pseudo C"
) -> 'LinearViewObject':
_settings = settings
if _settings is not None:
_settings = _settings.handle
- return LinearViewObject(core.BNCreateLinearViewSingleFunctionLanguageRepresentation(func.handle, _settings))
+ return LinearViewObject(core.BNCreateLinearViewSingleFunctionLanguageRepresentation(func.handle, _settings, language))
class LinearViewCursor:
diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py
index 02b070fa..4b76939f 100644
--- a/python/scriptingprovider.py
+++ b/python/scriptingprovider.py
@@ -1809,23 +1809,23 @@ def _get_current_il_function(instance: PythonScriptingInstance):
from binaryninja import FunctionGraphType
if instance.interpreter.locals["current_ui_view_location"] is not None:
ilType = instance.interpreter.locals["current_ui_view_location"].getILViewType()
- if ilType == FunctionGraphType.LowLevelILFunctionGraph:
+ if ilType.view_type == FunctionGraphType.LowLevelILFunctionGraph:
return instance.interpreter.locals["current_llil"]
- elif ilType == FunctionGraphType.LiftedILFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.LiftedILFunctionGraph:
return instance.interpreter.locals["current_lifted_il"]
- elif ilType == FunctionGraphType.LowLevelILSSAFormFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.LowLevelILSSAFormFunctionGraph:
return instance.interpreter.locals["current_llil_ssa"]
- elif ilType == FunctionGraphType.MappedMediumLevelILFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.MappedMediumLevelILFunctionGraph:
return instance.interpreter.locals["current_mapped_mlil"]
- elif ilType == FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph:
return instance.interpreter.locals["current_mapped_mlil_ssa"]
- elif ilType == FunctionGraphType.MediumLevelILFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.MediumLevelILFunctionGraph:
return instance.interpreter.locals["current_mlil"]
- elif ilType == FunctionGraphType.MediumLevelILSSAFormFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.MediumLevelILSSAFormFunctionGraph:
return instance.interpreter.locals["current_mlil_ssa"]
- elif ilType == FunctionGraphType.HighLevelILFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.HighLevelILFunctionGraph:
return instance.interpreter.locals["current_hlil"]
- elif ilType == FunctionGraphType.HighLevelILSSAFormFunctionGraph:
+ elif ilType.view_type == FunctionGraphType.HighLevelILSSAFormFunctionGraph:
return instance.interpreter.locals["current_hlil_ssa"]
return None
diff --git a/python/types.py b/python/types.py
index 2c2b652f..d5fd3544 100644
--- a/python/types.py
+++ b/python/types.py
@@ -20,7 +20,7 @@
import ctypes
import typing
-from typing import Generator, List, Union, Tuple, Optional, Iterable, Dict, Generic, TypeVar
+from typing import Generator, List, Union, Tuple, Optional, Iterable, Dict, Generic, TypeVar, Callable
from dataclasses import dataclass
import uuid
@@ -53,6 +53,7 @@ SomeType = Union['TypeBuilder', 'Type']
TypeContainerType = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary']
NameSpaceType = Optional[Union[str, List[str], 'NameSpace']]
TypeParserResult = typeparser.TypeParserResult
+ResolveMemberCallback = Callable[['NamedTypeReferenceType', 'StructureType', int, int, int, 'StructureMember'], None]
# The following are needed to prevent the type checker from getting
# confused as we have member functions in `Type` named the same thing
_int = int
@@ -384,6 +385,12 @@ class CoreSymbol:
def handle(self):
return self._handle
+ def imported_function_from_import_address_symbol(self, addr: int) -> Optional['CoreSymbol']:
+ sym = core.BNImportedFunctionFromImportAddressSymbol(self._handle, addr)
+ if sym is None:
+ return None
+ return CoreSymbol(sym)
+
class Symbol(CoreSymbol):
"""
@@ -2717,6 +2724,40 @@ class StructureType(Type):
ntr_type, guid, name, self.alignment, self.width, self.platform, self.confidence
)
+ def resolve_member_or_base_member(
+ self, view: Optional['binaryview.BinaryView'], offset: int, size: int,
+ resolve_func: ResolveMemberCallback, member_index_hint: Optional[int] = None
+ ) -> bool:
+ if view is not None:
+ view = view.handle
+
+ def resolve_member_callback(
+ ctxt, base_name: core.BNNamedTypeReferenceHandle, resolved_struct: core.BNStructureHandle,
+ member_index: int, struct_offset: int, adjusted_offset: int, member: core.BNStructureMember
+ ):
+ if base_name:
+ base_name = NamedTypeReferenceType.create_from_handle(core.BNNewNamedTypeReference(base_name))
+ if resolved_struct:
+ resolved_struct = StructureType.from_core_struct(core.BNNewStructureReference(resolved_struct))
+ t = Type.create(core.BNNewTypeReference(member.type), confidence=member.typeConfidence)
+ struct_member = StructureMember(
+ t, member.name, member.offset, MemberAccess(member.access), MemberScope(member.scope)
+ )
+ resolve_func(base_name, resolved_struct, member_index, struct_offset, adjusted_offset, struct_member)
+
+ member_index_hint_value = 0
+ if member_index_hint is not None:
+ member_index_hint_value = member_index_hint
+ return core.BNResolveStructureMemberOrBaseMember(
+ self.struct_handle, view, offset, size, None,
+ ctypes.CFUNCTYPE(
+ None, ctypes.c_void_p, core.BNNamedTypeReferenceHandle, core.BNStructureHandle, ctypes.c_size_t,
+ ctypes.c_uint64, ctypes.c_uint64, core.BNStructureMember
+ )(resolve_member_callback),
+ member_index_hint is not None,
+ member_index_hint_value
+ )
+
@property
def children(self) -> List[Type]:
return [member.type for member in self.members]
@@ -3064,6 +3105,30 @@ class FunctionType(Type):
return result
@property
+ def parameters_with_all_locations(self) -> List[FunctionParameter]:
+ """Type parameters list with default locations filled in with values (read-only)"""
+ count = ctypes.c_ulonglong()
+ params = core.BNGetTypeParameters(self._handle, count)
+ assert params is not None, "core.BNGetTypeParameters returned None"
+ result = []
+ for i in range(0, count.value):
+ param_type = Type.create(
+ core.BNNewTypeReference(params[i].type), platform=self._platform, confidence=params[i].typeConfidence
+ )
+ name = params[i].name
+ if (params[i].location.type
+ == VariableSourceType.RegisterVariableSourceType) and (self._platform is not None):
+ name = self._platform.arch.get_reg_name(params[i].location.storage)
+ elif params[i].location.type == VariableSourceType.StackVariableSourceType:
+ name = "arg_%x" % params[i].location.storage
+ param_location = variable.VariableNameAndType(
+ params[i].location.type, params[i].location.index, params[i].location.storage, name, param_type
+ )
+ result.append(FunctionParameter(param_type, params[i].name, param_location))
+ core.BNFreeTypeParameterList(params, count.value)
+ return result
+
+ @property
def has_variable_arguments(self) -> BoolWithConfidence:
"""Whether type has variable arguments (read-only)"""
result = core.BNTypeHasVariableArguments(self._handle)
diff --git a/python/variable.py b/python/variable.py
index 8ed3f545..7b4121bf 100644
--- a/python/variable.py
+++ b/python/variable.py
@@ -20,14 +20,14 @@
# IN THE SOFTWARE.
import ctypes
-from typing import List, Generator, Optional, Union, Set, Dict
+from typing import List, Generator, Optional, Union, Set, Dict, Tuple
from dataclasses import dataclass
import binaryninja
from . import _binaryninjacore as core
from . import databuffer
from . import decorators
-from .enums import RegisterValueType, VariableSourceType, DeadStoreElimination, FunctionGraphType
+from .enums import RegisterValueType, VariableSourceType, DeadStoreElimination, FunctionGraphType, BuiltinType
FunctionOrILFunction = Union["binaryninja.function.Function", "binaryninja.lowlevelil.LowLevelILFunction",
"binaryninja.mediumlevelil.MediumLevelILFunction",
@@ -223,6 +223,12 @@ class ConstantData(RegisterValue):
raise ValueError(f"ConstantData requires a Function instance: {self.size}")
return self.function.get_constant_data(self.type, self.value, self.size)
+ @property
+ def data_and_builtin(self) -> Tuple[databuffer.DataBuffer, BuiltinType]:
+ if self.function is None:
+ raise ValueError(f"ConstantData requires a Function instance: {self.size}")
+ return self.function.get_constant_data_and_builtin(self.type, self.value, self.size)
+
@dataclass(frozen=True)
class ValueRange: