summaryrefslogtreecommitdiff
path: root/python/examples/wf_test_copy_expr.py
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2025-06-30 13:46:52 -0400
committerGlenn Smith <glenn@vector35.com>2025-07-01 23:23:25 -0400
commit7871953325024282191116771022201477045749 (patch)
tree2e55b48cd8c2152ebeae85d1f617c9287628c762 /python/examples/wf_test_copy_expr.py
parent3369388279087234793382558126227582393316 (diff)
Python: Collect and pass mappings when copying MLIL functions
Diffstat (limited to 'python/examples/wf_test_copy_expr.py')
-rw-r--r--python/examples/wf_test_copy_expr.py59
1 files changed, 53 insertions, 6 deletions
diff --git a/python/examples/wf_test_copy_expr.py b/python/examples/wf_test_copy_expr.py
index 7a3da06c..77e6e159 100644
--- a/python/examples/wf_test_copy_expr.py
+++ b/python/examples/wf_test_copy_expr.py
@@ -1,3 +1,4 @@
+import functools
import json
import math
@@ -67,7 +68,14 @@ def assert_llil_eq(old_insn: LowLevelILInstruction, new_insn: LowLevelILInstruct
assert old_op[1] == new_op[1], err_msg
-def assert_mlil_eq(old_insn: LowLevelILInstruction, new_insn: LowLevelILInstruction):
+@functools.lru_cache(maxsize=8)
+def get_mlil_maps(mlil: MediumLevelILFunction, builders: bool) -> Tuple[LLILSSAToMLILInstructionMapping, LLILSSAToMLILExpressionMapping]:
+ instr_map = mlil._get_llil_ssa_to_mlil_instr_map(builders)
+ expr_map = mlil._get_llil_ssa_to_mlil_expr_map(builders)
+ return instr_map, expr_map
+
+
+def assert_mlil_eq(old_insn: MediumLevelILInstruction, new_insn: MediumLevelILInstruction):
"""
Make sure that these two instructions are the same (probably correct). Asserts otherwise.
@@ -78,10 +86,23 @@ def assert_mlil_eq(old_insn: LowLevelILInstruction, new_insn: LowLevelILInstruct
"""
err_msg = (hex(old_insn.address), old_insn, new_insn)
assert old_insn.operation == new_insn.operation, err_msg
- # assert old_insn.attributes == new_insn.attributes, err_msg
+ assert old_insn.attributes == new_insn.attributes, err_msg
assert old_insn.size == new_insn.size, err_msg
assert old_insn.source_location == new_insn.source_location, err_msg
assert len(old_insn.operands) == len(new_insn.operands), err_msg
+ # Type only applies once we've generated SSA form (probably not consistent)
+ # assert old_insn.expr_type == new_insn.expr_type, f"{err_msg} {old_insn.expr_type} {new_insn.expr_type}"
+
+ instr_map, expr_map = get_mlil_maps(new_insn.function, True)
+
+ # Compare that the instruction's LLIL SSA map is the same as the old function
+ if old_insn.instr_index is not None and old_insn.function.get_expr_index_for_instruction(old_insn.instr_index) == old_insn.expr_index:
+ old_llil_ssa = old_insn.function.get_low_level_il_instruction_index(old_insn.instr_index)
+ if old_llil_ssa is not None:
+ assert [mlil for (llil, mlil) in instr_map.items() if llil == old_llil_ssa] == [new_insn.instr_index], err_msg
+ else:
+ assert [mlil for (llil, mlil) in instr_map.items() if llil == old_llil_ssa] == [], err_msg
+
# Can't compare operands directly since IL expression indices might change when
# copying an instruction to another function
for i, (old_op, new_op) in enumerate(zip(old_insn.detailed_operands, new_insn.detailed_operands)):
@@ -231,6 +252,11 @@ def mlil_action(context: AnalysisContext):
report.append(FlowGraphReport("new graph", new_mlil.create_graph_immediate(settings)))
show_report_collection("copy expr test", report)
+ # Check expr mappings are the same
+ new_map = list(sorted(new_mlil._get_llil_ssa_to_mlil_expr_map(True), key=lambda o: (o.lower_index, o.higher_index)))
+ old_map = list(sorted(old_mlil._get_llil_ssa_to_mlil_expr_map(False), key=lambda o: (o.lower_index, o.higher_index)))
+ assert old_map == new_map
+
# Check all BBs have all the same instructions
# Technically, this misses any instructions outside a BB, but those are not
# picked up by analysis anyway, and therefore don't matter.
@@ -240,15 +266,26 @@ def mlil_action(context: AnalysisContext):
for old_insn, new_insn in zip(old_bb, new_bb):
assert_mlil_eq(old_insn, new_insn)
+ # Make sure mappings update correctly following set
+ new_map = list(sorted(new_mlil._get_llil_ssa_to_mlil_expr_map(True), key=lambda o: (o.lower_index, o.higher_index)))
+ context.mlil = new_mlil
+ newer_map = list(sorted(context.mlil._get_llil_ssa_to_mlil_expr_map(False), key=lambda o: (o.lower_index, o.higher_index)))
+ assert new_map == newer_map
+
-wf = Workflow("core.function.metaAnalysis").clone("TestCopyExpr")
+wf = Workflow("core.function.metaAnalysis").clone("core.function.metaAnalysis")
# Define the custom activity configuration
wf.register_activity(Activity(
configuration=json.dumps({
"name": "extension.test_copy_expr.lil_action",
"title": "Lifted IL copy_expr Test",
- "description": "Makes sure copy_expr works on Lifted IL functions."
+ "description": "Makes sure copy_expr works on Lifted IL functions.",
+ "eligibility": {
+ "auto": {
+ "default": False
+ }
+ }
}),
action=lil_action
))
@@ -256,7 +293,12 @@ wf.register_activity(Activity(
configuration=json.dumps({
"name": "extension.test_copy_expr.llil_action",
"title": "Low Level IL copy_expr Test",
- "description": "Makes sure copy_expr works on Low Level IL functions."
+ "description": "Makes sure copy_expr works on Low Level IL functions.",
+ "eligibility": {
+ "auto": {
+ "default": False
+ }
+ }
}),
action=llil_action
))
@@ -264,7 +306,12 @@ wf.register_activity(Activity(
configuration=json.dumps({
"name": "extension.test_copy_expr.mlil_action",
"title": "Medium Level IL copy_expr Test",
- "description": "Makes sure copy_expr works on Medium Level IL functions."
+ "description": "Makes sure copy_expr works on Medium Level IL functions.",
+ "eligibility": {
+ "auto": {
+ "default": False
+ }
+ }
}),
action=mlil_action
))