angr 9.2.158__cp310-abi3-win_amd64.whl → 9.2.159__cp310-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/ailment/__init__.py +81 -0
- angr/ailment/block.py +81 -0
- angr/ailment/block_walker.py +845 -0
- angr/ailment/constant.py +3 -0
- angr/ailment/converter_common.py +11 -0
- angr/ailment/converter_pcode.py +623 -0
- angr/ailment/converter_vex.py +798 -0
- angr/ailment/expression.py +1639 -0
- angr/ailment/manager.py +33 -0
- angr/ailment/statement.py +978 -0
- angr/ailment/tagged_object.py +61 -0
- angr/ailment/utils.py +114 -0
- angr/analyses/calling_convention/calling_convention.py +6 -2
- angr/analyses/decompiler/ail_simplifier.py +5 -5
- angr/analyses/decompiler/block_io_finder.py +4 -4
- angr/analyses/decompiler/block_similarity.py +2 -2
- angr/analyses/decompiler/block_simplifier.py +4 -4
- angr/analyses/decompiler/callsite_maker.py +2 -2
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +1 -1
- angr/analyses/decompiler/clinic.py +1 -1
- angr/analyses/decompiler/condition_processor.py +1 -1
- angr/analyses/decompiler/counters/boolean_counter.py +4 -4
- angr/analyses/decompiler/counters/call_counter.py +4 -4
- angr/analyses/decompiler/counters/expression_counters.py +5 -5
- angr/analyses/decompiler/counters/seq_cf_structure_counter.py +1 -1
- angr/analyses/decompiler/decompiler.py +5 -3
- angr/analyses/decompiler/dephication/dephication_base.py +12 -1
- angr/analyses/decompiler/dephication/graph_dephication.py +12 -5
- angr/analyses/decompiler/dephication/graph_rewriting.py +6 -10
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +109 -72
- angr/analyses/decompiler/dephication/rewriting_engine.py +32 -9
- angr/analyses/decompiler/dephication/seqnode_dephication.py +32 -10
- angr/analyses/decompiler/empty_node_remover.py +2 -2
- angr/analyses/decompiler/expression_narrower.py +6 -6
- angr/analyses/decompiler/goto_manager.py +2 -2
- angr/analyses/decompiler/jump_target_collector.py +1 -1
- angr/analyses/decompiler/label_collector.py +1 -1
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +25 -25
- angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +1 -1
- angr/analyses/decompiler/optimization_passes/code_motion.py +2 -2
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +3 -3
- angr/analyses/decompiler/optimization_passes/const_derefs.py +3 -3
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +4 -4
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +2 -2
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +3 -3
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +4 -4
- angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +1 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +4 -4
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +3 -3
- angr/analyses/decompiler/optimization_passes/engine_base.py +1 -1
- angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +3 -3
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +4 -4
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +25 -1
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +4 -4
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +2 -2
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +3 -3
- angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +3 -3
- angr/analyses/decompiler/optimization_passes/tag_slicer.py +1 -1
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/base.py +3 -3
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/bswap.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +3 -3
- angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/rol_ror.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/utils.py +1 -1
- angr/analyses/decompiler/redundant_label_remover.py +1 -1
- angr/analyses/decompiler/region_identifier.py +4 -4
- angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -1
- angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +1 -1
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +37 -8
- angr/analyses/decompiler/region_simplifiers/goto.py +1 -1
- angr/analyses/decompiler/region_simplifiers/if_.py +1 -1
- angr/analyses/decompiler/region_simplifiers/loop.py +1 -1
- angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -1
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +14 -2
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +3 -3
- angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +1 -1
- angr/analyses/decompiler/return_maker.py +1 -1
- angr/analyses/decompiler/seq_to_blocks.py +1 -1
- angr/analyses/decompiler/sequence_walker.py +2 -2
- angr/analyses/decompiler/ssailification/rewriting.py +4 -4
- angr/analyses/decompiler/ssailification/rewriting_engine.py +4 -4
- angr/analyses/decompiler/ssailification/rewriting_state.py +3 -3
- angr/analyses/decompiler/ssailification/ssailification.py +2 -2
- angr/analyses/decompiler/ssailification/traversal.py +1 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +11 -2
- angr/analyses/decompiler/structured_codegen/c.py +3 -3
- angr/analyses/decompiler/structuring/dream.py +1 -1
- angr/analyses/decompiler/structuring/phoenix.py +3 -3
- angr/analyses/decompiler/structuring/structurer_base.py +1 -1
- angr/analyses/decompiler/structuring/structurer_nodes.py +1 -2
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/deobfuscator/string_obf_opt_passes.py +3 -3
- angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +2 -2
- angr/analyses/propagator/propagator.py +1 -1
- angr/analyses/proximity_graph.py +2 -2
- angr/analyses/reaching_definitions/engine_ail.py +1 -1
- angr/analyses/reaching_definitions/reaching_definitions.py +1 -1
- angr/analyses/reaching_definitions/subject.py +1 -1
- angr/analyses/s_liveness.py +2 -2
- angr/analyses/s_propagator.py +3 -3
- angr/analyses/s_reaching_definitions/s_rda_model.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +3 -3
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -3
- angr/analyses/variable_recovery/engine_ail.py +2 -2
- angr/analyses/variable_recovery/engine_base.py +1 -1
- angr/analyses/variable_recovery/variable_recovery_base.py +1 -1
- angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
- angr/engines/light/data.py +1 -1
- angr/engines/light/engine.py +1 -1
- angr/knowledge_plugins/key_definitions/atoms.py +1 -1
- angr/knowledge_plugins/propagations/prop_value.py +1 -1
- angr/knowledge_plugins/propagations/propagation_model.py +1 -1
- angr/knowledge_plugins/propagations/states.py +1 -1
- angr/knowledge_plugins/variables/variable_manager.py +1 -1
- angr/lib/angr_native.dll +0 -0
- angr/rustylib.pyd +0 -0
- angr/utils/ail.py +4 -4
- angr/utils/endness.py +1 -1
- angr/utils/ssa/__init__.py +14 -4
- angr/utils/ssa/tmp_uses_collector.py +4 -4
- angr/utils/ssa/vvar_uses_collector.py +4 -4
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/METADATA +6 -6
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/RECORD +192 -180
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/WHEEL +0 -0
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/entry_points.txt +0 -0
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,845 @@
|
|
|
1
|
+
# pylint:disable=unused-argument,no-self-use
|
|
2
|
+
# pyright: reportIncompatibleMethodOverride=false
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Any
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
|
|
7
|
+
from . import Block
|
|
8
|
+
from .statement import (
|
|
9
|
+
Call,
|
|
10
|
+
CAS,
|
|
11
|
+
Statement,
|
|
12
|
+
ConditionalJump,
|
|
13
|
+
Assignment,
|
|
14
|
+
Store,
|
|
15
|
+
Return,
|
|
16
|
+
Jump,
|
|
17
|
+
DirtyStatement,
|
|
18
|
+
WeakAssignment,
|
|
19
|
+
)
|
|
20
|
+
from .expression import (
|
|
21
|
+
Load,
|
|
22
|
+
Expression,
|
|
23
|
+
BinaryOp,
|
|
24
|
+
UnaryOp,
|
|
25
|
+
Convert,
|
|
26
|
+
ITE,
|
|
27
|
+
DirtyExpression,
|
|
28
|
+
VEXCCallExpression,
|
|
29
|
+
Tmp,
|
|
30
|
+
Register,
|
|
31
|
+
Const,
|
|
32
|
+
Reinterpret,
|
|
33
|
+
MultiStatementExpression,
|
|
34
|
+
VirtualVariable,
|
|
35
|
+
Phi,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AILBlockWalkerBase:
|
|
40
|
+
"""
|
|
41
|
+
Walks all statements and expressions of an AIL node and do nothing.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, stmt_handlers=None, expr_handlers=None):
|
|
45
|
+
_default_stmt_handlers = {
|
|
46
|
+
Assignment: self._handle_Assignment,
|
|
47
|
+
WeakAssignment: self._handle_WeakAssignment,
|
|
48
|
+
CAS: self._handle_CAS,
|
|
49
|
+
Call: self._handle_Call,
|
|
50
|
+
Store: self._handle_Store,
|
|
51
|
+
ConditionalJump: self._handle_ConditionalJump,
|
|
52
|
+
Jump: self._handle_Jump,
|
|
53
|
+
Return: self._handle_Return,
|
|
54
|
+
DirtyStatement: self._handle_DirtyStatement,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_default_expr_handlers = {
|
|
58
|
+
Call: self._handle_CallExpr,
|
|
59
|
+
Load: self._handle_Load,
|
|
60
|
+
BinaryOp: self._handle_BinaryOp,
|
|
61
|
+
UnaryOp: self._handle_UnaryOp,
|
|
62
|
+
Convert: self._handle_Convert,
|
|
63
|
+
ITE: self._handle_ITE,
|
|
64
|
+
DirtyExpression: self._handle_DirtyExpression,
|
|
65
|
+
VEXCCallExpression: self._handle_VEXCCallExpression,
|
|
66
|
+
Tmp: self._handle_Tmp,
|
|
67
|
+
Register: self._handle_Register,
|
|
68
|
+
Reinterpret: self._handle_Reinterpret,
|
|
69
|
+
Const: self._handle_Const,
|
|
70
|
+
MultiStatementExpression: self._handle_MultiStatementExpression,
|
|
71
|
+
VirtualVariable: self._handle_VirtualVariable,
|
|
72
|
+
Phi: self._handle_Phi,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
self.stmt_handlers: dict[type, Callable] = stmt_handlers if stmt_handlers else _default_stmt_handlers
|
|
76
|
+
self.expr_handlers: dict[type, Callable] = expr_handlers if expr_handlers else _default_expr_handlers
|
|
77
|
+
|
|
78
|
+
def walk(self, block: Block) -> None:
|
|
79
|
+
i = 0
|
|
80
|
+
while i < len(block.statements):
|
|
81
|
+
stmt = block.statements[i]
|
|
82
|
+
self._handle_stmt(i, stmt, block)
|
|
83
|
+
i += 1
|
|
84
|
+
|
|
85
|
+
def walk_statement(self, stmt: Statement, block: Block | None = None):
|
|
86
|
+
return self._handle_stmt(0, stmt, block)
|
|
87
|
+
|
|
88
|
+
def walk_expression(
|
|
89
|
+
self,
|
|
90
|
+
expr: Expression,
|
|
91
|
+
stmt_idx: int | None = None,
|
|
92
|
+
stmt: Statement | None = None,
|
|
93
|
+
block: Block | None = None,
|
|
94
|
+
):
|
|
95
|
+
return self._handle_expr(0, expr, stmt_idx or 0, stmt, block)
|
|
96
|
+
|
|
97
|
+
def _handle_stmt(self, stmt_idx: int, stmt: Statement, block: Block | None) -> Any:
|
|
98
|
+
try:
|
|
99
|
+
handler = self.stmt_handlers[type(stmt)]
|
|
100
|
+
except KeyError:
|
|
101
|
+
handler = None
|
|
102
|
+
|
|
103
|
+
if handler:
|
|
104
|
+
return handler(stmt_idx, stmt, block)
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
def _handle_expr(
|
|
108
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
109
|
+
) -> Any:
|
|
110
|
+
try:
|
|
111
|
+
handler = self.expr_handlers[type(expr)]
|
|
112
|
+
except KeyError:
|
|
113
|
+
handler = None
|
|
114
|
+
|
|
115
|
+
if handler:
|
|
116
|
+
return handler(expr_idx, expr, stmt_idx, stmt, block)
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# Default handlers
|
|
121
|
+
#
|
|
122
|
+
|
|
123
|
+
def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Block | None):
|
|
124
|
+
self._handle_expr(0, stmt.dst, stmt_idx, stmt, block)
|
|
125
|
+
self._handle_expr(1, stmt.src, stmt_idx, stmt, block)
|
|
126
|
+
|
|
127
|
+
def _handle_WeakAssignment(self, stmt_idx: int, stmt: WeakAssignment, block: Block | None):
|
|
128
|
+
self._handle_expr(0, stmt.dst, stmt_idx, stmt, block)
|
|
129
|
+
self._handle_expr(1, stmt.src, stmt_idx, stmt, block)
|
|
130
|
+
|
|
131
|
+
def _handle_CAS(self, stmt_idx: int, stmt: CAS, block: Block | None):
|
|
132
|
+
self._handle_expr(0, stmt.addr, stmt_idx, stmt, block)
|
|
133
|
+
self._handle_expr(1, stmt.data_lo, stmt_idx, stmt, block)
|
|
134
|
+
if stmt.data_hi is not None:
|
|
135
|
+
self._handle_expr(2, stmt.data_hi, stmt_idx, stmt, block)
|
|
136
|
+
self._handle_expr(3, stmt.expd_lo, stmt_idx, stmt, block)
|
|
137
|
+
if stmt.expd_hi is not None:
|
|
138
|
+
self._handle_expr(4, stmt.expd_hi, stmt_idx, stmt, block)
|
|
139
|
+
self._handle_expr(5, stmt.old_lo, stmt_idx, stmt, block)
|
|
140
|
+
if stmt.old_hi is not None:
|
|
141
|
+
self._handle_expr(6, stmt.old_hi, stmt_idx, stmt, block)
|
|
142
|
+
|
|
143
|
+
def _handle_Call(self, stmt_idx: int, stmt: Call, block: Block | None):
|
|
144
|
+
if not isinstance(stmt.target, str):
|
|
145
|
+
self._handle_expr(-1, stmt.target, stmt_idx, stmt, block)
|
|
146
|
+
if stmt.args:
|
|
147
|
+
for i, arg in enumerate(stmt.args):
|
|
148
|
+
self._handle_expr(i, arg, stmt_idx, stmt, block)
|
|
149
|
+
|
|
150
|
+
def _handle_Store(self, stmt_idx: int, stmt: Store, block: Block | None):
|
|
151
|
+
self._handle_expr(0, stmt.addr, stmt_idx, stmt, block)
|
|
152
|
+
self._handle_expr(1, stmt.data, stmt_idx, stmt, block)
|
|
153
|
+
if stmt.guard is not None:
|
|
154
|
+
self._handle_expr(2, stmt.guard, stmt_idx, stmt, block)
|
|
155
|
+
|
|
156
|
+
def _handle_Jump(self, stmt_idx: int, stmt: Jump, block: Block | None):
|
|
157
|
+
self._handle_expr(0, stmt.target, stmt_idx, stmt, block)
|
|
158
|
+
|
|
159
|
+
def _handle_ConditionalJump(self, stmt_idx: int, stmt: ConditionalJump, block: Block | None):
|
|
160
|
+
self._handle_expr(0, stmt.condition, stmt_idx, stmt, block)
|
|
161
|
+
if stmt.true_target is not None:
|
|
162
|
+
self._handle_expr(1, stmt.true_target, stmt_idx, stmt, block)
|
|
163
|
+
if stmt.false_target is not None:
|
|
164
|
+
self._handle_expr(2, stmt.false_target, stmt_idx, stmt, block)
|
|
165
|
+
|
|
166
|
+
def _handle_Return(self, stmt_idx: int, stmt: Return, block: Block | None):
|
|
167
|
+
if stmt.ret_exprs:
|
|
168
|
+
for i, ret_expr in enumerate(stmt.ret_exprs):
|
|
169
|
+
self._handle_expr(i, ret_expr, stmt_idx, stmt, block)
|
|
170
|
+
|
|
171
|
+
def _handle_DirtyStatement(self, stmt_idx: int, stmt: DirtyStatement, block: Block | None):
|
|
172
|
+
self._handle_expr(0, stmt.dirty, stmt_idx, stmt, block)
|
|
173
|
+
|
|
174
|
+
def _handle_Load(self, expr_idx: int, expr: Load, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
175
|
+
self._handle_expr(0, expr.addr, stmt_idx, stmt, block)
|
|
176
|
+
|
|
177
|
+
def _handle_CallExpr(self, expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
178
|
+
if not isinstance(expr.target, str):
|
|
179
|
+
self._handle_expr(-1, expr.target, stmt_idx, stmt, block)
|
|
180
|
+
if expr.args:
|
|
181
|
+
for i, arg in enumerate(expr.args):
|
|
182
|
+
self._handle_expr(i, arg, stmt_idx, stmt, block)
|
|
183
|
+
|
|
184
|
+
def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
185
|
+
self._handle_expr(0, expr.operands[0], stmt_idx, stmt, block)
|
|
186
|
+
self._handle_expr(1, expr.operands[1], stmt_idx, stmt, block)
|
|
187
|
+
|
|
188
|
+
def _handle_UnaryOp(self, expr_idx: int, expr: UnaryOp, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
189
|
+
self._handle_expr(0, expr.operand, stmt_idx, stmt, block)
|
|
190
|
+
|
|
191
|
+
def _handle_Convert(self, expr_idx: int, expr: Convert, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
192
|
+
self._handle_expr(expr_idx, expr.operand, stmt_idx, stmt, block)
|
|
193
|
+
|
|
194
|
+
def _handle_Reinterpret(
|
|
195
|
+
self, expr_idx: int, expr: Reinterpret, stmt_idx: int, stmt: Statement, block: Block | None
|
|
196
|
+
):
|
|
197
|
+
self._handle_expr(expr_idx, expr.operand, stmt_idx, stmt, block)
|
|
198
|
+
|
|
199
|
+
def _handle_ITE(self, expr_idx: int, expr: ITE, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
200
|
+
self._handle_expr(0, expr.cond, stmt_idx, stmt, block)
|
|
201
|
+
self._handle_expr(1, expr.iftrue, stmt_idx, stmt, block)
|
|
202
|
+
self._handle_expr(2, expr.iffalse, stmt_idx, stmt, block)
|
|
203
|
+
|
|
204
|
+
def _handle_Tmp(self, expr_idx: int, expr: Tmp, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
def _handle_Register(self, expr_idx: int, expr: Register, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
def _handle_Const(self, expr_idx: int, expr: Const, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def _handle_VirtualVariable(
|
|
214
|
+
self, expr_idx: int, expr: VirtualVariable, stmt_idx: int, stmt: Statement, block: Block | None
|
|
215
|
+
):
|
|
216
|
+
pass
|
|
217
|
+
|
|
218
|
+
def _handle_Phi(self, expr_id: int, expr: Phi, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
219
|
+
for idx, (_, vvar) in enumerate(expr.src_and_vvars):
|
|
220
|
+
if vvar is not None:
|
|
221
|
+
self._handle_expr(idx, vvar, stmt_idx, stmt, block)
|
|
222
|
+
|
|
223
|
+
def _handle_MultiStatementExpression(
|
|
224
|
+
self, expr_idx, expr: MultiStatementExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
225
|
+
):
|
|
226
|
+
for idx, stmt_ in enumerate(expr.stmts):
|
|
227
|
+
self._handle_stmt(idx, stmt_, None)
|
|
228
|
+
self._handle_expr(0, expr.expr, stmt_idx, stmt, block)
|
|
229
|
+
|
|
230
|
+
def _handle_DirtyExpression(
|
|
231
|
+
self, expr_idx: int, expr: DirtyExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
232
|
+
):
|
|
233
|
+
for idx, operand in enumerate(expr.operands):
|
|
234
|
+
self._handle_expr(idx, operand, stmt_idx, stmt, block)
|
|
235
|
+
if expr.guard is not None:
|
|
236
|
+
self._handle_expr(len(expr.operands) + 1, expr.guard, stmt_idx, stmt, block)
|
|
237
|
+
|
|
238
|
+
def _handle_VEXCCallExpression(
|
|
239
|
+
self, expr_idx: int, expr: VEXCCallExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
240
|
+
):
|
|
241
|
+
for idx, operand in enumerate(expr.operands):
|
|
242
|
+
self._handle_expr(idx, operand, stmt_idx, stmt, block)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class AILBlockWalker(AILBlockWalkerBase):
|
|
246
|
+
"""
|
|
247
|
+
Walks all statements and expressions of an AIL node, and rebuilds expressions, statements, or blocks if needed.
|
|
248
|
+
|
|
249
|
+
If you need a pure walker without rebuilding, use AILBlockWalkerBase instead.
|
|
250
|
+
|
|
251
|
+
:ivar update_block: True if the block should be updated in place, False if a new block should be created and
|
|
252
|
+
returned as the result of walk().
|
|
253
|
+
:ivar replace_phi_stmt: True if you want _handle_Phi be called and vvars potentially replaced; False otherwise.
|
|
254
|
+
Default to False because in the most majority cases you do not want vvars in a Phi
|
|
255
|
+
variable be replaced.
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
def __init__(
|
|
259
|
+
self, stmt_handlers=None, expr_handlers=None, update_block: bool = True, replace_phi_stmt: bool = False
|
|
260
|
+
):
|
|
261
|
+
super().__init__(stmt_handlers=stmt_handlers, expr_handlers=expr_handlers)
|
|
262
|
+
self._update_block = update_block
|
|
263
|
+
self._replace_phi_stmt = replace_phi_stmt
|
|
264
|
+
|
|
265
|
+
def walk(self, block: Block) -> Block | None:
|
|
266
|
+
"""
|
|
267
|
+
Walk the block and rebuild it if necessary. The block will be rebuilt in-place (by updating statements in the
|
|
268
|
+
original block when self._update_block is set to True), or a new block will be created and returned.
|
|
269
|
+
|
|
270
|
+
:param block: The block to walk.
|
|
271
|
+
:return: The new block that is rebuilt, or None if the block is not changed or when self._update_block
|
|
272
|
+
is set to True.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
changed = False
|
|
276
|
+
new_block: Block | None = None
|
|
277
|
+
|
|
278
|
+
i = 0
|
|
279
|
+
while i < len(block.statements):
|
|
280
|
+
stmt = block.statements[i]
|
|
281
|
+
new_stmt = self._handle_stmt(i, stmt, block)
|
|
282
|
+
if new_stmt is not None:
|
|
283
|
+
changed = True
|
|
284
|
+
if not self._update_block:
|
|
285
|
+
if new_block is None:
|
|
286
|
+
new_block = block.copy(statements=block.statements[:i])
|
|
287
|
+
new_block.statements.append(new_stmt)
|
|
288
|
+
else:
|
|
289
|
+
if new_block is not None:
|
|
290
|
+
new_block.statements.append(stmt)
|
|
291
|
+
i += 1
|
|
292
|
+
|
|
293
|
+
return new_block if changed else None
|
|
294
|
+
|
|
295
|
+
def _handle_stmt(self, stmt_idx: int, stmt: Statement, block: Block | None) -> Any:
|
|
296
|
+
try:
|
|
297
|
+
handler = self.stmt_handlers[type(stmt)]
|
|
298
|
+
except KeyError:
|
|
299
|
+
handler = None
|
|
300
|
+
|
|
301
|
+
if handler:
|
|
302
|
+
return handler(stmt_idx, stmt, block)
|
|
303
|
+
return None
|
|
304
|
+
|
|
305
|
+
def _handle_expr(
|
|
306
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
307
|
+
) -> Any:
|
|
308
|
+
try:
|
|
309
|
+
handler = self.expr_handlers[type(expr)]
|
|
310
|
+
except KeyError:
|
|
311
|
+
handler = None
|
|
312
|
+
|
|
313
|
+
if handler:
|
|
314
|
+
expr = handler(expr_idx, expr, stmt_idx, stmt, block)
|
|
315
|
+
if expr is not None:
|
|
316
|
+
r = self._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
|
|
317
|
+
return r if r is not None else expr
|
|
318
|
+
return None # unchanged
|
|
319
|
+
|
|
320
|
+
#
|
|
321
|
+
# Default handlers
|
|
322
|
+
#
|
|
323
|
+
|
|
324
|
+
def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Block | None) -> Assignment | None:
|
|
325
|
+
changed = False
|
|
326
|
+
|
|
327
|
+
dst = self._handle_expr(0, stmt.dst, stmt_idx, stmt, block)
|
|
328
|
+
if dst is not None and dst is not stmt.dst:
|
|
329
|
+
changed = True
|
|
330
|
+
else:
|
|
331
|
+
dst = stmt.dst
|
|
332
|
+
|
|
333
|
+
src = self._handle_expr(1, stmt.src, stmt_idx, stmt, block)
|
|
334
|
+
if src is not None and src is not stmt.src:
|
|
335
|
+
changed = True
|
|
336
|
+
else:
|
|
337
|
+
src = stmt.src
|
|
338
|
+
|
|
339
|
+
if changed:
|
|
340
|
+
# update the statement directly in the block
|
|
341
|
+
new_stmt = Assignment(stmt.idx, dst, src, **stmt.tags)
|
|
342
|
+
if self._update_block and block is not None:
|
|
343
|
+
block.statements[stmt_idx] = new_stmt
|
|
344
|
+
return new_stmt
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
def _handle_WeakAssignment(self, stmt_idx: int, stmt: WeakAssignment, block: Block | None) -> WeakAssignment | None:
|
|
348
|
+
changed = False
|
|
349
|
+
|
|
350
|
+
dst = self._handle_expr(0, stmt.dst, stmt_idx, stmt, block)
|
|
351
|
+
if dst is not None and dst is not stmt.dst:
|
|
352
|
+
changed = True
|
|
353
|
+
else:
|
|
354
|
+
dst = stmt.dst
|
|
355
|
+
|
|
356
|
+
src = self._handle_expr(1, stmt.src, stmt_idx, stmt, block)
|
|
357
|
+
if src is not None and src is not stmt.src:
|
|
358
|
+
changed = True
|
|
359
|
+
else:
|
|
360
|
+
src = stmt.src
|
|
361
|
+
|
|
362
|
+
if changed:
|
|
363
|
+
# update the statement directly in the block
|
|
364
|
+
new_stmt = WeakAssignment(stmt.idx, dst, src, **stmt.tags)
|
|
365
|
+
if self._update_block and block is not None:
|
|
366
|
+
block.statements[stmt_idx] = new_stmt
|
|
367
|
+
return new_stmt
|
|
368
|
+
return None
|
|
369
|
+
|
|
370
|
+
def _handle_CAS(self, stmt_idx: int, stmt: CAS, block: Block | None) -> CAS | None:
|
|
371
|
+
changed = False
|
|
372
|
+
|
|
373
|
+
addr = self._handle_expr(0, stmt.addr, stmt_idx, stmt, block)
|
|
374
|
+
if addr is not None and addr is not stmt.addr:
|
|
375
|
+
changed = True
|
|
376
|
+
else:
|
|
377
|
+
addr = stmt.addr
|
|
378
|
+
|
|
379
|
+
data_lo = self._handle_expr(1, stmt.data_lo, stmt_idx, stmt, block)
|
|
380
|
+
if data_lo is not None and data_lo is not stmt.data_lo:
|
|
381
|
+
changed = True
|
|
382
|
+
else:
|
|
383
|
+
data_lo = stmt.data_lo
|
|
384
|
+
|
|
385
|
+
data_hi = None
|
|
386
|
+
if stmt.data_hi is not None:
|
|
387
|
+
data_hi = self._handle_expr(2, stmt.data_hi, stmt_idx, stmt, block)
|
|
388
|
+
if data_hi is not None and data_hi is not stmt.data_hi:
|
|
389
|
+
changed = True
|
|
390
|
+
else:
|
|
391
|
+
data_hi = stmt.data_hi
|
|
392
|
+
|
|
393
|
+
expd_lo = self._handle_expr(3, stmt.expd_lo, stmt_idx, stmt, block)
|
|
394
|
+
if expd_lo is not None and expd_lo is not stmt.expd_lo:
|
|
395
|
+
changed = True
|
|
396
|
+
else:
|
|
397
|
+
expd_lo = stmt.expd_lo
|
|
398
|
+
|
|
399
|
+
expd_hi = None
|
|
400
|
+
if stmt.expd_hi is not None:
|
|
401
|
+
expd_hi = self._handle_expr(4, stmt.expd_hi, stmt_idx, stmt, block)
|
|
402
|
+
if expd_hi is not None and expd_hi is not stmt.expd_hi:
|
|
403
|
+
changed = True
|
|
404
|
+
else:
|
|
405
|
+
expd_hi = stmt.expd_hi
|
|
406
|
+
|
|
407
|
+
old_lo = self._handle_expr(5, stmt.old_lo, stmt_idx, stmt, block)
|
|
408
|
+
if old_lo is not None and old_lo is not stmt.old_lo:
|
|
409
|
+
changed = True
|
|
410
|
+
else:
|
|
411
|
+
old_lo = stmt.old_lo
|
|
412
|
+
|
|
413
|
+
old_hi = None
|
|
414
|
+
if stmt.old_hi is not None:
|
|
415
|
+
old_hi = self._handle_expr(6, stmt.old_hi, stmt_idx, stmt, block)
|
|
416
|
+
if old_hi is not None and old_hi is not stmt.old_hi:
|
|
417
|
+
changed = True
|
|
418
|
+
else:
|
|
419
|
+
old_hi = stmt.old_hi
|
|
420
|
+
|
|
421
|
+
if changed:
|
|
422
|
+
# update the statement directly in the block
|
|
423
|
+
new_stmt = CAS(
|
|
424
|
+
stmt.idx,
|
|
425
|
+
addr,
|
|
426
|
+
data_lo,
|
|
427
|
+
data_hi,
|
|
428
|
+
expd_lo,
|
|
429
|
+
expd_hi,
|
|
430
|
+
old_lo,
|
|
431
|
+
old_hi,
|
|
432
|
+
stmt.endness,
|
|
433
|
+
**stmt.tags,
|
|
434
|
+
)
|
|
435
|
+
if self._update_block and block is not None:
|
|
436
|
+
block.statements[stmt_idx] = new_stmt
|
|
437
|
+
return new_stmt
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
def _handle_Call(self, stmt_idx: int, stmt: Call, block: Block | None):
|
|
441
|
+
changed = False
|
|
442
|
+
|
|
443
|
+
if isinstance(stmt.target, str):
|
|
444
|
+
new_target = None
|
|
445
|
+
else:
|
|
446
|
+
new_target = self._handle_expr(-1, stmt.target, stmt_idx, stmt, block)
|
|
447
|
+
if new_target is not None and new_target is not stmt.target:
|
|
448
|
+
changed = True
|
|
449
|
+
|
|
450
|
+
new_args = None
|
|
451
|
+
if stmt.args is not None:
|
|
452
|
+
new_args = []
|
|
453
|
+
|
|
454
|
+
i = 0
|
|
455
|
+
while i < len(stmt.args):
|
|
456
|
+
arg = stmt.args[i]
|
|
457
|
+
new_arg = self._handle_expr(i, arg, stmt_idx, stmt, block)
|
|
458
|
+
if new_arg is not None and new_arg is not arg:
|
|
459
|
+
if not changed:
|
|
460
|
+
# initialize new_args
|
|
461
|
+
new_args = list(stmt.args[:i])
|
|
462
|
+
new_args.append(new_arg)
|
|
463
|
+
changed = True
|
|
464
|
+
else:
|
|
465
|
+
if changed:
|
|
466
|
+
new_args.append(arg)
|
|
467
|
+
i += 1
|
|
468
|
+
|
|
469
|
+
if changed:
|
|
470
|
+
new_stmt = Call(
|
|
471
|
+
stmt.idx,
|
|
472
|
+
new_target if new_target is not None else stmt.target,
|
|
473
|
+
calling_convention=stmt.calling_convention,
|
|
474
|
+
prototype=stmt.prototype,
|
|
475
|
+
args=new_args,
|
|
476
|
+
ret_expr=stmt.ret_expr,
|
|
477
|
+
**stmt.tags,
|
|
478
|
+
)
|
|
479
|
+
if self._update_block and block is not None:
|
|
480
|
+
block.statements[stmt_idx] = new_stmt
|
|
481
|
+
return new_stmt
|
|
482
|
+
return None
|
|
483
|
+
|
|
484
|
+
def _handle_Store(self, stmt_idx: int, stmt: Store, block: Block | None):
|
|
485
|
+
changed = False
|
|
486
|
+
|
|
487
|
+
addr = self._handle_expr(0, stmt.addr, stmt_idx, stmt, block)
|
|
488
|
+
if addr is not None and addr is not stmt.addr:
|
|
489
|
+
changed = True
|
|
490
|
+
else:
|
|
491
|
+
addr = stmt.addr
|
|
492
|
+
|
|
493
|
+
data = self._handle_expr(1, stmt.data, stmt_idx, stmt, block)
|
|
494
|
+
if data is not None and data is not stmt.data:
|
|
495
|
+
changed = True
|
|
496
|
+
else:
|
|
497
|
+
data = stmt.data
|
|
498
|
+
|
|
499
|
+
guard = None if stmt.guard is None else self._handle_expr(2, stmt.guard, stmt_idx, stmt, block)
|
|
500
|
+
if guard is not None and guard is not stmt.guard:
|
|
501
|
+
changed = True
|
|
502
|
+
else:
|
|
503
|
+
guard = stmt.guard
|
|
504
|
+
|
|
505
|
+
if changed:
|
|
506
|
+
# update the statement directly in the block
|
|
507
|
+
new_stmt = Store(
|
|
508
|
+
stmt.idx,
|
|
509
|
+
addr,
|
|
510
|
+
data,
|
|
511
|
+
stmt.size,
|
|
512
|
+
stmt.endness,
|
|
513
|
+
guard=guard,
|
|
514
|
+
variable=stmt.variable,
|
|
515
|
+
offset=stmt.offset,
|
|
516
|
+
**stmt.tags,
|
|
517
|
+
)
|
|
518
|
+
if self._update_block and block is not None:
|
|
519
|
+
block.statements[stmt_idx] = new_stmt
|
|
520
|
+
return new_stmt
|
|
521
|
+
return None
|
|
522
|
+
|
|
523
|
+
def _handle_Jump(self, stmt_idx: int, stmt: Jump, block: Block | None):
|
|
524
|
+
changed = False
|
|
525
|
+
|
|
526
|
+
target = self._handle_expr(0, stmt.target, stmt_idx, stmt, block)
|
|
527
|
+
if target is not None and target is not stmt.target:
|
|
528
|
+
changed = True
|
|
529
|
+
else:
|
|
530
|
+
target = stmt.target
|
|
531
|
+
|
|
532
|
+
if changed:
|
|
533
|
+
new_stmt = Jump(
|
|
534
|
+
stmt.idx,
|
|
535
|
+
target,
|
|
536
|
+
target_idx=stmt.target_idx,
|
|
537
|
+
**stmt.tags,
|
|
538
|
+
)
|
|
539
|
+
if self._update_block and block is not None:
|
|
540
|
+
block.statements[stmt_idx] = new_stmt
|
|
541
|
+
return new_stmt
|
|
542
|
+
return None
|
|
543
|
+
|
|
544
|
+
def _handle_ConditionalJump(self, stmt_idx: int, stmt: ConditionalJump, block: Block | None):
|
|
545
|
+
changed = False
|
|
546
|
+
|
|
547
|
+
condition = self._handle_expr(0, stmt.condition, stmt_idx, stmt, block)
|
|
548
|
+
if condition is not None and condition is not stmt.condition:
|
|
549
|
+
changed = True
|
|
550
|
+
else:
|
|
551
|
+
condition = stmt.condition
|
|
552
|
+
|
|
553
|
+
true_target = None
|
|
554
|
+
if stmt.true_target is not None:
|
|
555
|
+
true_target = self._handle_expr(1, stmt.true_target, stmt_idx, stmt, block)
|
|
556
|
+
if true_target is not None and true_target is not stmt.true_target:
|
|
557
|
+
changed = True
|
|
558
|
+
else:
|
|
559
|
+
true_target = stmt.true_target
|
|
560
|
+
|
|
561
|
+
false_target = None
|
|
562
|
+
if stmt.false_target is not None:
|
|
563
|
+
false_target = self._handle_expr(2, stmt.false_target, stmt_idx, stmt, block)
|
|
564
|
+
if false_target is not None and false_target is not stmt.false_target:
|
|
565
|
+
changed = True
|
|
566
|
+
else:
|
|
567
|
+
false_target = stmt.false_target
|
|
568
|
+
|
|
569
|
+
if changed:
|
|
570
|
+
new_stmt = ConditionalJump(
|
|
571
|
+
stmt.idx,
|
|
572
|
+
condition,
|
|
573
|
+
true_target,
|
|
574
|
+
false_target,
|
|
575
|
+
true_target_idx=stmt.true_target_idx,
|
|
576
|
+
false_target_idx=stmt.false_target_idx,
|
|
577
|
+
**stmt.tags,
|
|
578
|
+
)
|
|
579
|
+
if self._update_block and block is not None:
|
|
580
|
+
block.statements[stmt_idx] = new_stmt
|
|
581
|
+
return new_stmt
|
|
582
|
+
return None
|
|
583
|
+
|
|
584
|
+
def _handle_Return(self, stmt_idx: int, stmt: Return, block: Block | None):
|
|
585
|
+
if stmt.ret_exprs:
|
|
586
|
+
i = 0
|
|
587
|
+
changed = False
|
|
588
|
+
new_ret_exprs = [None] * len(stmt.ret_exprs)
|
|
589
|
+
while i < len(stmt.ret_exprs):
|
|
590
|
+
new_ret_expr = self._handle_expr(i, stmt.ret_exprs[i], stmt_idx, stmt, block)
|
|
591
|
+
if new_ret_expr is not None:
|
|
592
|
+
new_ret_exprs[i] = new_ret_expr
|
|
593
|
+
changed = True
|
|
594
|
+
else:
|
|
595
|
+
new_ret_exprs[i] = stmt.ret_exprs[i]
|
|
596
|
+
i += 1
|
|
597
|
+
|
|
598
|
+
if changed:
|
|
599
|
+
new_stmt = Return(stmt.idx, new_ret_exprs, **stmt.tags)
|
|
600
|
+
if self._update_block and block is not None:
|
|
601
|
+
block.statements[stmt_idx] = new_stmt
|
|
602
|
+
return new_stmt
|
|
603
|
+
return None
|
|
604
|
+
|
|
605
|
+
def _handle_DirtyStatement(self, stmt_idx: int, stmt: DirtyStatement, block: Block | None):
|
|
606
|
+
changed = False
|
|
607
|
+
|
|
608
|
+
dirty = self._handle_expr(0, stmt.dirty, stmt_idx, stmt, block)
|
|
609
|
+
if dirty is not None and dirty is not stmt.dirty:
|
|
610
|
+
changed = True
|
|
611
|
+
else:
|
|
612
|
+
dirty = stmt.dirty
|
|
613
|
+
|
|
614
|
+
if changed:
|
|
615
|
+
new_stmt = DirtyStatement(stmt.idx, dirty, **stmt.tags)
|
|
616
|
+
if self._update_block and block is not None:
|
|
617
|
+
block.statements[stmt_idx] = new_stmt
|
|
618
|
+
return new_stmt
|
|
619
|
+
return None
|
|
620
|
+
|
|
621
|
+
#
|
|
622
|
+
# Expression handlers
|
|
623
|
+
#
|
|
624
|
+
|
|
625
|
+
def _handle_Load(self, expr_idx: int, expr: Load, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
626
|
+
addr = self._handle_expr(0, expr.addr, stmt_idx, stmt, block)
|
|
627
|
+
|
|
628
|
+
if addr is not None and addr is not expr.addr:
|
|
629
|
+
new_expr = expr.copy()
|
|
630
|
+
new_expr.addr = addr
|
|
631
|
+
return new_expr
|
|
632
|
+
return None
|
|
633
|
+
|
|
634
|
+
def _handle_CallExpr(self, expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
635
|
+
changed = False
|
|
636
|
+
|
|
637
|
+
if isinstance(expr.target, str):
|
|
638
|
+
new_target = None
|
|
639
|
+
else:
|
|
640
|
+
new_target = self._handle_expr(-1, expr.target, stmt_idx, stmt, block)
|
|
641
|
+
if new_target is not None and new_target is not expr.target:
|
|
642
|
+
changed = True
|
|
643
|
+
|
|
644
|
+
new_args = None
|
|
645
|
+
if expr.args is not None:
|
|
646
|
+
i = 0
|
|
647
|
+
new_args = []
|
|
648
|
+
while i < len(expr.args):
|
|
649
|
+
arg = expr.args[i]
|
|
650
|
+
new_arg = self._handle_expr(i, arg, stmt_idx, stmt, block)
|
|
651
|
+
if new_arg is not None and new_arg is not arg:
|
|
652
|
+
if not changed:
|
|
653
|
+
# initialize new_args
|
|
654
|
+
new_args = list(expr.args[:i])
|
|
655
|
+
new_args.append(new_arg)
|
|
656
|
+
changed = True
|
|
657
|
+
else:
|
|
658
|
+
if changed:
|
|
659
|
+
new_args.append(arg)
|
|
660
|
+
i += 1
|
|
661
|
+
|
|
662
|
+
if changed:
|
|
663
|
+
expr = expr.copy()
|
|
664
|
+
if new_target is not None:
|
|
665
|
+
expr.target = new_target
|
|
666
|
+
expr.args = new_args
|
|
667
|
+
return expr
|
|
668
|
+
return None
|
|
669
|
+
|
|
670
|
+
def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
671
|
+
changed = False
|
|
672
|
+
|
|
673
|
+
operand_0 = self._handle_expr(0, expr.operands[0], stmt_idx, stmt, block)
|
|
674
|
+
if operand_0 is not None and operand_0 is not expr.operands[0]:
|
|
675
|
+
changed = True
|
|
676
|
+
else:
|
|
677
|
+
operand_0 = expr.operands[0]
|
|
678
|
+
|
|
679
|
+
operand_1 = self._handle_expr(1, expr.operands[1], stmt_idx, stmt, block)
|
|
680
|
+
if operand_1 is not None and operand_1 is not expr.operands[1]:
|
|
681
|
+
changed = True
|
|
682
|
+
else:
|
|
683
|
+
operand_1 = expr.operands[1]
|
|
684
|
+
|
|
685
|
+
if changed:
|
|
686
|
+
new_expr = expr.copy()
|
|
687
|
+
new_expr.operands = (operand_0, operand_1)
|
|
688
|
+
new_expr.depth = max(operand_0.depth, operand_1.depth) + 1
|
|
689
|
+
return new_expr
|
|
690
|
+
return None
|
|
691
|
+
|
|
692
|
+
def _handle_UnaryOp(self, expr_idx: int, expr: UnaryOp, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
693
|
+
new_operand = self._handle_expr(0, expr.operand, stmt_idx, stmt, block)
|
|
694
|
+
if new_operand is not None and new_operand is not expr.operand:
|
|
695
|
+
new_expr = expr.copy()
|
|
696
|
+
new_expr.operand = new_operand
|
|
697
|
+
return new_expr
|
|
698
|
+
return None
|
|
699
|
+
|
|
700
|
+
def _handle_Convert(self, expr_idx: int, expr: Convert, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
701
|
+
new_operand = self._handle_expr(expr_idx, expr.operand, stmt_idx, stmt, block)
|
|
702
|
+
if new_operand is not None and new_operand is not expr.operand:
|
|
703
|
+
return Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, new_operand, **expr.tags)
|
|
704
|
+
return None
|
|
705
|
+
|
|
706
|
+
def _handle_Reinterpret(
|
|
707
|
+
self, expr_idx: int, expr: Reinterpret, stmt_idx: int, stmt: Statement, block: Block | None
|
|
708
|
+
):
|
|
709
|
+
new_operand = self._handle_expr(expr_idx, expr.operand, stmt_idx, stmt, block)
|
|
710
|
+
if new_operand is not None and new_operand is not expr.operand:
|
|
711
|
+
return Reinterpret(
|
|
712
|
+
expr.idx, expr.from_bits, expr.from_type, expr.to_bits, expr.to_type, new_operand, **expr.tags
|
|
713
|
+
)
|
|
714
|
+
return None
|
|
715
|
+
|
|
716
|
+
def _handle_ITE(self, expr_idx: int, expr: ITE, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
717
|
+
changed = False
|
|
718
|
+
|
|
719
|
+
cond = self._handle_expr(0, expr.cond, stmt_idx, stmt, block)
|
|
720
|
+
if cond is not None and cond is not expr.cond:
|
|
721
|
+
changed = True
|
|
722
|
+
else:
|
|
723
|
+
cond = expr.cond
|
|
724
|
+
|
|
725
|
+
iftrue = self._handle_expr(1, expr.iftrue, stmt_idx, stmt, block)
|
|
726
|
+
if iftrue is not None and iftrue is not expr.iftrue:
|
|
727
|
+
changed = True
|
|
728
|
+
else:
|
|
729
|
+
iftrue = expr.iftrue
|
|
730
|
+
|
|
731
|
+
iffalse = self._handle_expr(2, expr.iffalse, stmt_idx, stmt, block)
|
|
732
|
+
if iffalse is not None and iffalse is not expr.iffalse:
|
|
733
|
+
changed = True
|
|
734
|
+
else:
|
|
735
|
+
iffalse = expr.iffalse
|
|
736
|
+
|
|
737
|
+
if changed:
|
|
738
|
+
new_expr = expr.copy()
|
|
739
|
+
new_expr.cond = cond
|
|
740
|
+
new_expr.iftrue = iftrue
|
|
741
|
+
new_expr.iffalse = iffalse
|
|
742
|
+
return new_expr
|
|
743
|
+
return None
|
|
744
|
+
|
|
745
|
+
def _handle_Phi(self, expr_id: int, expr: Phi, stmt_idx: int, stmt: Statement, block: Block | None) -> Phi | None:
|
|
746
|
+
if not self._replace_phi_stmt:
|
|
747
|
+
# fallback to the read-only version
|
|
748
|
+
return super()._handle_Phi(expr_id, expr, stmt_idx, stmt, block)
|
|
749
|
+
|
|
750
|
+
changed = False
|
|
751
|
+
|
|
752
|
+
src_and_vvars = []
|
|
753
|
+
for idx, (src, vvar) in enumerate(expr.src_and_vvars):
|
|
754
|
+
if vvar is None:
|
|
755
|
+
if src_and_vvars is not None:
|
|
756
|
+
src_and_vvars.append((src, None))
|
|
757
|
+
continue
|
|
758
|
+
new_vvar = self._handle_expr(idx, vvar, stmt_idx, stmt, block)
|
|
759
|
+
if new_vvar is not None and new_vvar is not vvar:
|
|
760
|
+
changed = True
|
|
761
|
+
if src_and_vvars is None:
|
|
762
|
+
src_and_vvars = expr.src_and_vvars[:idx]
|
|
763
|
+
src_and_vvars.append((src, new_vvar))
|
|
764
|
+
elif src_and_vvars is not None:
|
|
765
|
+
src_and_vvars.append((src, vvar))
|
|
766
|
+
|
|
767
|
+
return Phi(expr.idx, expr.bits, src_and_vvars, **expr.tags) if changed else None
|
|
768
|
+
|
|
769
|
+
def _handle_DirtyExpression(
|
|
770
|
+
self, expr_idx: int, expr: DirtyExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
771
|
+
):
|
|
772
|
+
changed = False
|
|
773
|
+
new_operands = []
|
|
774
|
+
for operand in expr.operands:
|
|
775
|
+
new_operand = self._handle_expr(0, operand, stmt_idx, stmt, block)
|
|
776
|
+
if new_operand is not None and new_operand is not operand:
|
|
777
|
+
changed = True
|
|
778
|
+
new_operands.append(new_operand)
|
|
779
|
+
else:
|
|
780
|
+
new_operands.append(operand)
|
|
781
|
+
|
|
782
|
+
new_guard = expr.guard
|
|
783
|
+
if expr.guard is not None:
|
|
784
|
+
new_guard = self._handle_expr(2, expr.guard, stmt_idx, stmt, block)
|
|
785
|
+
if new_guard is not None and new_guard is not expr.guard:
|
|
786
|
+
changed = True
|
|
787
|
+
|
|
788
|
+
if changed:
|
|
789
|
+
return DirtyExpression(
|
|
790
|
+
expr.idx,
|
|
791
|
+
expr.callee,
|
|
792
|
+
new_operands,
|
|
793
|
+
guard=new_guard,
|
|
794
|
+
mfx=expr.mfx,
|
|
795
|
+
maddr=expr.maddr,
|
|
796
|
+
msize=expr.msize,
|
|
797
|
+
bits=expr.bits,
|
|
798
|
+
**expr.tags,
|
|
799
|
+
)
|
|
800
|
+
return None
|
|
801
|
+
|
|
802
|
+
def _handle_VEXCCallExpression(
|
|
803
|
+
self, expr_idx: int, expr: VEXCCallExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
804
|
+
):
|
|
805
|
+
changed = False
|
|
806
|
+
new_operands = []
|
|
807
|
+
for idx, operand in enumerate(expr.operands):
|
|
808
|
+
new_operand = self._handle_expr(idx, operand, stmt_idx, stmt, block)
|
|
809
|
+
if new_operand is not None and new_operand is not operand:
|
|
810
|
+
changed = True
|
|
811
|
+
new_operands.append(new_operand)
|
|
812
|
+
else:
|
|
813
|
+
new_operands.append(operand)
|
|
814
|
+
|
|
815
|
+
if changed:
|
|
816
|
+
new_expr = expr.copy()
|
|
817
|
+
new_expr.operands = tuple(new_operands)
|
|
818
|
+
return new_expr
|
|
819
|
+
return None
|
|
820
|
+
|
|
821
|
+
def _handle_MultiStatementExpression(
|
|
822
|
+
self, expr_idx, expr: MultiStatementExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
823
|
+
):
|
|
824
|
+
changed = False
|
|
825
|
+
new_statements = []
|
|
826
|
+
for idx, stmt_ in enumerate(expr.stmts):
|
|
827
|
+
new_stmt = self._handle_stmt(idx, stmt_, None)
|
|
828
|
+
if new_stmt is not None and new_stmt is not stmt_:
|
|
829
|
+
changed = True
|
|
830
|
+
new_statements.append(new_stmt)
|
|
831
|
+
else:
|
|
832
|
+
new_statements.append(stmt_)
|
|
833
|
+
|
|
834
|
+
new_expr = self._handle_expr(0, expr.expr, stmt_idx, stmt, block)
|
|
835
|
+
if new_expr is not None and new_expr is not expr.expr:
|
|
836
|
+
changed = True
|
|
837
|
+
else:
|
|
838
|
+
new_expr = expr.expr
|
|
839
|
+
|
|
840
|
+
if changed:
|
|
841
|
+
expr_ = expr.copy()
|
|
842
|
+
expr_.expr = new_expr
|
|
843
|
+
expr_.stmts = new_statements
|
|
844
|
+
return expr_
|
|
845
|
+
return None
|