summaryrefslogtreecommitdiff
path: root/python/mediumlevelil.py
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-12-23 13:12:02 -0700
committerRusty Wagner <rusty.wagner@gmail.com>2026-05-22 16:30:56 -0400
commit8d621c51b2797fda7b1dc22243dde611cfc04f68 (patch)
treeba5e6a90e644d21d13e75dabcbd0cc747444443a /python/mediumlevelil.py
parent08e34ac325743085911f96b62c81d9a1f2127806 (diff)
Refactor calling conventions to support correct representation of structures
Diffstat (limited to 'python/mediumlevelil.py')
-rw-r--r--python/mediumlevelil.py262
1 files changed, 258 insertions, 4 deletions
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index 1a42fe27..155a3751 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -219,7 +219,11 @@ class MediumLevelILInstruction(BaseILInstruction):
MediumLevelILOperation.MLIL_VAR: [("src", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [
("src", "var"), ("offset", "int")
], MediumLevelILOperation.MLIL_VAR_SPLIT: [("high", "var"), ("low", "var")],
- MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [
+ MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_PASS_BY_REF: [
+ ("src", "expr")
+ ], MediumLevelILOperation.MLIL_RETURN_BY_REF: [
+ ("src", "expr")
+ ], MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [
("src", "var"), ("offset", "int")
], MediumLevelILOperation.MLIL_CONST: [("constant", "int")], MediumLevelILOperation.MLIL_CONST_PTR: [
("constant", "int")
@@ -279,9 +283,15 @@ class MediumLevelILInstruction(BaseILInstruction):
("params", "expr_list")
], MediumLevelILOperation.MLIL_VAR_OUTPUT: [
("dest", "var")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD: [
+ ("dest", "var"), ("offset", "int")
+ ], MediumLevelILOperation.MLIL_STORE_OUTPUT: [
+ ("dest", "expr")
], MediumLevelILOperation.MLIL_RET: [
("src", "expr_list")
- ], MediumLevelILOperation.MLIL_NORET: [], MediumLevelILOperation.MLIL_IF: [
+ ], MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND: [
+ ("src", "expr_list")
+ ], MediumLevelILOperation.MLIL_NORET: [], MediumLevelILOperation.MLIL_IF: [
("condition", "expr"), ("true", "int"), ("false", "int")
], MediumLevelILOperation.MLIL_GOTO: [("dest", "int")], MediumLevelILOperation.MLIL_CMP_E: [
("left", "expr"), ("right", "expr")
@@ -377,6 +387,12 @@ class MediumLevelILInstruction(BaseILInstruction):
("high", "var_ssa"), ("low", "var_ssa")
], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA: [
("dest", "var_ssa")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA_FIELD: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED_FIELD: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int")
], MediumLevelILOperation.MLIL_CALL_SSA: [
("output", "expr"), ("output_dest_memory", "int"), ("dest", "expr"),
("params", "expr_list"), ("src_memory", "int")
@@ -1158,13 +1174,25 @@ class MediumLevelILInstruction(BaseILInstruction):
return result
def _var_written_for_function_call_output(self) -> Optional[variable.Variable]:
+ if isinstance(self, MediumLevelILReturnByRef):
+ return self.src._var_written_for_function_call_output()
if isinstance(self, MediumLevelILVarOutput):
return self.dest
+ if isinstance(self, MediumLevelILVarOutputField):
+ return self.dest
return None
def _ssa_var_written_for_function_call_output(self) -> Optional[SSAVariable]:
+ if isinstance(self, MediumLevelILReturnByRef):
+ return self.src._ssa_var_written_for_function_call_output()
if isinstance(self, MediumLevelILVarOutputSsa):
return self.dest
+ if isinstance(self, MediumLevelILVarOutputSsaField):
+ return self.dest
+ if isinstance(self, MediumLevelILVarOutputAliased):
+ return self.dest
+ if isinstance(self, MediumLevelILVarOutputAliasedField):
+ return self.dest
return None
@@ -1324,6 +1352,16 @@ class MediumLevelILAddressOf(MediumLevelILInstruction):
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILPassByRef(MediumLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILReturnByRef(MediumLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILConst(MediumLevelILConstBase):
@property
def constant(self) -> int:
@@ -1503,6 +1541,37 @@ class MediumLevelILVarOutput(MediumLevelILInstruction, RegisterStack):
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputField(MediumLevelILInstruction, SetVar):
+ @property
+ def dest(self) -> variable.Variable:
+ return self._get_var(0)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(1)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'Variable'),
+ ('offset', self.offset, 'int')
+ ]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILStoreOutput(MediumLevelILInstruction, Store):
+ @property
+ def dest(self) -> MediumLevelILInstruction:
+ return self._get_expr(0)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ("dest", self.dest, "MediumLevelILInstruction"),
+ ]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILRet(MediumLevelILInstruction, Return):
@property
def src(self) -> List[MediumLevelILInstruction]:
@@ -1667,6 +1736,94 @@ class MediumLevelILVarOutputSsa(MediumLevelILInstruction, SSAVariableInstruction
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputSsaField(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(3)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable'),
+ ('offset', self.offset, 'int')
+ ]
+
+ @property
+ def vars_read(self) -> List[SSAVariable]:
+ return [self.prev] # type: ignore # we're guaranteed not to return non-SSAVariables here
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputAliased(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable')
+ ]
+
+ @property
+ def vars_read(self) -> List[Union[variable.Variable, SSAVariable]]:
+ return []
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputAliasedField(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(3)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable'),
+ ('offset', self.offset, 'int')
+ ]
+
+ @property
+ def vars_read(self) -> List[SSAVariable]:
+ return [self.prev] # type: ignore # we're guaranteed not to return non-SSAVariables here
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILVarAliased(MediumLevelILInstruction, SSA, AliasedVariableInstruction):
@property
def src(self) -> SSAVariable:
@@ -3230,6 +3387,15 @@ class MediumLevelILForceVerSsa(MediumLevelILInstruction, SSA):
def src(self) -> SSAVariable:
return self._get_var_ssa(2, 3)
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILBlockToExpand(MediumLevelILInstruction):
+ @property
+ def exprs(self) -> List[MediumLevelILInstruction]:
+ return self._get_expr_list(0, 1)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [("exprs", self.exprs, "List[MediumLevelILInstruction]")]
ILInstruction = {
@@ -3241,6 +3407,8 @@ ILInstruction = {
MediumLevelILOperation.MLIL_LOAD: MediumLevelILLoad, # [("src", "expr")],
MediumLevelILOperation.MLIL_VAR: MediumLevelILVar, # [("src", "var")],
MediumLevelILOperation.MLIL_ADDRESS_OF: MediumLevelILAddressOf, # [("src", "var")],
+ MediumLevelILOperation.MLIL_PASS_BY_REF: MediumLevelILPassByRef, # [("src", "expr")],
+ MediumLevelILOperation.MLIL_RETURN_BY_REF: MediumLevelILReturnByRef, # [("src", "expr")],
MediumLevelILOperation.MLIL_CONST: MediumLevelILConst, # [("constant", "int")],
MediumLevelILOperation.MLIL_CONST_PTR: MediumLevelILConstPtr, # [("constant", "int")],
MediumLevelILOperation.MLIL_FLOAT_CONST: MediumLevelILFloatConst, # [("constant", "float")],
@@ -3285,6 +3453,8 @@ ILInstruction = {
MediumLevelILOperation.MLIL_SEPARATE_PARAM_LIST: MediumLevelILSeparateParamList, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_SHARED_PARAM_SLOT: MediumLevelILSharedParamSlot, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_VAR_OUTPUT: MediumLevelILVarOutput, # [("dest", "var")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD: MediumLevelILVarOutputField, # [("dest", "var"), ("offset", "int")],
+ MediumLevelILOperation.MLIL_STORE_OUTPUT: MediumLevelILStoreOutput, # [("dest", "expr")],
MediumLevelILOperation.MLIL_RET: MediumLevelILRet, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_GOTO: MediumLevelILGoto, # [("dest", "int")],
MediumLevelILOperation.MLIL_BOOL_TO_INT: MediumLevelILBoolToInt, # [("src", "expr")],
@@ -3305,6 +3475,12 @@ ILInstruction = {
MediumLevelILOperation.MLIL_VAR_SSA: MediumLevelILVarSsa, # [("src", "var_ssa")],
MediumLevelILOperation.MLIL_VAR_ALIASED: MediumLevelILVarAliased, # [("src", "var_ssa")],
MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA: MediumLevelILVarOutputSsa, # [("dest", "var_ssa")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA_FIELD:
+ MediumLevelILVarOutputSsaField, # [("prev", "var_ssa_dest_and_src"), ("offset", "int")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED:
+ MediumLevelILVarOutputAliased, # [("prev", "var_ssa_dest_and_src")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED_FIELD:
+ MediumLevelILVarOutputAliasedField, # [("prev", "var_ssa_dest_and_src"), ("offset", "int")],
MediumLevelILOperation.MLIL_CMP_E: MediumLevelILCmpE, # [("left", "expr"), ("right", "expr")],
MediumLevelILOperation.MLIL_CMP_NE: MediumLevelILCmpNe, # [("left", "expr"), ("right", "expr")],
MediumLevelILOperation.MLIL_CMP_SLT: MediumLevelILCmpSlt, # [("left", "expr"), ("right", "expr")],
@@ -3399,6 +3575,7 @@ ILInstruction = {
MediumLevelILOperation.MLIL_ASSERT_SSA: MediumLevelILAssertSsa,
MediumLevelILOperation.MLIL_FORCE_VER: MediumLevelILForceVer,
MediumLevelILOperation.MLIL_FORCE_VER_SSA: MediumLevelILForceVerSsa,
+ MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND: MediumLevelILBlockToExpand, # [("exprs", "expr_list")],
}
@@ -3857,6 +4034,9 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_VAR_OUTPUT:
expr: MediumLevelILVarOutput
return dest.var_output(expr.size, expr.dest, loc)
+ if expr.operation == MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD:
+ expr: MediumLevelILVarOutputField
+ return dest.var_output_field(expr.size, expr.dest, expr.offset, loc)
if expr.operation == MediumLevelILOperation.MLIL_FORCE_VER:
expr: MediumLevelILForceVer
return dest.force_ver(expr.size, expr.dest, expr.src, loc)
@@ -3937,6 +4117,9 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_STORE_STRUCT:
expr: MediumLevelILStoreStruct
return dest.store_struct(expr.size, sub_expr_handler(expr.dest), expr.offset, sub_expr_handler(expr.src), loc)
+ if expr.operation == MediumLevelILOperation.MLIL_STORE_OUTPUT:
+ expr: MediumLevelILStoreOutput
+ return dest.store_output(expr.size, sub_expr_handler(expr.dest), loc)
if expr.operation == MediumLevelILOperation.MLIL_LOAD:
expr: MediumLevelILLoad
return dest.load(expr.size, sub_expr_handler(expr.src), loc)
@@ -3964,7 +4147,9 @@ class MediumLevelILFunction:
MediumLevelILOperation.MLIL_ROUND_TO_INT,
MediumLevelILOperation.MLIL_FLOOR,
MediumLevelILOperation.MLIL_CEIL,
- MediumLevelILOperation.MLIL_FTRUNC
+ MediumLevelILOperation.MLIL_FTRUNC,
+ MediumLevelILOperation.MLIL_PASS_BY_REF,
+ MediumLevelILOperation.MLIL_RETURN_BY_REF
]:
expr: MediumLevelILUnaryBase
return dest.expr(expr.operation, sub_expr_handler(expr.src), size=expr.size, source_location=loc)
@@ -4097,6 +4282,10 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_UNIMPL:
expr: MediumLevelILUnimpl
return dest.unimplemented(loc)
+ if expr.operation == MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND:
+ expr: MediumLevelILBlockToExpand
+ params = [sub_expr_handler(src) for src in expr.src]
+ return dest.block_to_expand(params, loc)
raise NotImplementedError(f"unknown expr operation {expr.operation} in copy_expr_to")
new_index = do_copy(expr, dest, sub_expr_handler)
@@ -4410,6 +4599,20 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_STORE_STRUCT, dest, offset, src, size=size, source_location=loc)
+ def store_output(
+ self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None
+ ) -> ExpressionIndex:
+ """
+ ``store_output`` Outputs ``size`` bytes to expression ``dest`` as the result of a call
+
+ :param int size: number of bytes to write
+ :param ExpressionIndex dest: the expression to write to
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``[dest].size``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_STORE_OUTPUT, dest, size=size, source_location=loc)
+
def var(self, size: int, src: 'variable.CoreVariable', loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``var`` returns the variable ``src`` of size ``size``
@@ -4454,7 +4657,7 @@ class MediumLevelILFunction:
def var_output(self, size: int, dest: 'variable.CoreVariable', loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
- ``var`` returns the output variable ``dest`` of size ``size``
+ ``var_output`` returns the output variable ``dest`` of size ``size``
:param int size: the size of the variable in bytes
:param Variable dest: the variable being written
@@ -4464,6 +4667,21 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_VAR_OUTPUT, dest.identifier, size=size, source_location=loc)
+ def var_output_field(
+ self, size: int, dest: 'variable.CoreVariable', offset: int, loc: Optional['ILSourceLocation'] = None
+ ) -> ExpressionIndex:
+ """
+ ``var_output_field`` returns the output field at offset ``offset`` from variable ``dest`` of size ``size``
+
+ :param int size: the size of the field in bytes
+ :param Variable dest: the variable being written
+ :param int offset: offset of field in the variable
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``var:offset.size``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD, dest.identifier, offset, size=size, source_location=loc)
+
def assert_expr(
self,
size: int,
@@ -4516,6 +4734,30 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_ADDRESS_OF, var.identifier, size=0, source_location=loc)
+ def pass_by_ref(self, size: int, value: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``pass_by_ref`` indicates that ``value`` is being passed by reference to a call with a pointer size of ``size``
+
+ :param int size: the size of the pointer in bytes
+ :param ExpressionIndex value: the expression containing the reference being passed
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref *value``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_PASS_BY_REF, value, size=size, source_location=loc)
+
+ def return_by_ref(self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``return_by_ref`` indicates that ``dest`` is being returned by passing a reference to a call
+
+ :param int size: the size of the value in bytes
+ :param ExpressionIndex dest: the expression containing the target of the return value
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref dest``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_RETURN_BY_REF, dest, size=size, source_location=loc)
+
def address_of_field(self, var: 'variable.CoreVariable', offset: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``address_of_field`` takes the address of ``var`` at the offset ``offset``
@@ -5956,6 +6198,18 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_FCMP_UO, a, b, size=size, source_location=loc)
+ def block_to_expand(self, exprs: List[ExpressionIndex], loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``block_to_expand`` returns an expression to expand into multiple expressions. This expression must
+ be expanded by a future workflow step and is used temporarily to insert instructions.
+
+ :param List[ExpressionIndex] exprs: list of expressions
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``{ exprs... }``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND, len(exprs), self.add_operand_list(exprs), size=0, source_location=loc)
+
def goto(
self, label: MediumLevelILLabel, loc: Optional['ILSourceLocation'] = None
) -> ExpressionIndex: