Source code for binexport.operand
from __future__ import annotations
from functools import cached_property
from typing import TYPE_CHECKING
from binexport.expression import ExpressionBinExport
from binexport.types import ExpressionType
if TYPE_CHECKING:
import weakref
from .program import ProgramBinExport
from .function import FunctionBinExport
from .instruction import InstructionBinExport
from .binexport2_pb2 import BinExport2
[docs]
class OperandBinExport:
"""
Operand object.
Provide access to the underlying expression.
"""
def __init__(
self,
program: weakref.ref[ProgramBinExport],
function: weakref.ref[FunctionBinExport],
instruction: weakref.ref[InstructionBinExport],
op_idx: int,
):
"""
:param program: Weak reference to the program
:param function: Weak reference to the function
:param instruction: Weak reference to the instruction
:param op_idx: operand index in protobuf structure
"""
self._program = program
self._function = function
self._instruction = instruction
self._idx = op_idx
def __str__(self) -> str:
"""
Formatted string of the operand (shown in-order)
:return: string of the operand
"""
class Tree:
def __init__(self, expr: ExpressionBinExport):
self.children = []
self.expr = expr
def __str__(self) -> str:
if len(self.children) == 2: # Binary operator
left = str(self.children[0])
right = str(self.children[1])
return f"{left}{self.expr.value}{right}"
inv = {"{": "}", "[": "]", "!": ""}
final_s = ""
if self.expr.type != ExpressionType.SIZE: # Ignore SIZE
if isinstance(self.expr.value, int):
final_s += hex(self.expr.value)
else:
final_s += str(self.expr.value)
final_s += ",".join(str(child) for child in self.children)
if self.expr.type == ExpressionType.SYMBOL and self.expr.value in inv:
final_s += inv[self.expr.value]
return final_s
tree = {}
for expr in self.expressions:
tree[expr] = Tree(expr)
if expr.parent:
tree[expr.parent].children.append(tree[expr])
else:
root = expr
if tree:
return str(tree[root])
else:
return ""
def __repr__(self) -> str:
return f"<{type(self).__name__} {str(self)}>"
@property
def program(self) -> ProgramBinExport:
"""
Program object associated to this operand.
"""
return self._program()
@property
def function(self) -> FunctionBinExport:
"""
Function object associated to this operand.
"""
return self._function()
@property
def instruction(self) -> InstructionBinExport:
"""
Instruction object associated to this operand.
"""
return self._instruction()
@property
def pb_operand(self) -> BinExport2.Operand:
"""
Protobuf operand object in the protobuf structure.
"""
return self.program.proto.operand[self._idx]
@cached_property
def expressions(self) -> list[ExpressionBinExport]:
"""
Iterates over all the operand expression in a pre-order manner
(binary operator first).
The list is cached by default, to erase the cache delete the attribute
:return: list of expressions
"""
expr_dict = {} # {expression protobuf idx : ExpressionBinExport}
for exp_idx in self.pb_operand.expression_index:
parent = None
if self.program.proto.expression[exp_idx].HasField("parent_index"):
parent = expr_dict[self.program.proto.expression[exp_idx].parent_index]
expr_dict[exp_idx] = ExpressionBinExport(
self.program, self.function, self.instruction, exp_idx, parent
)
return list(expr_dict.values())