angr 9.2.158__cp310-abi3-macosx_11_0_arm64.whl → 9.2.159__cp310-abi3-macosx_11_0_arm64.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.

Files changed (192) hide show
  1. angr/__init__.py +1 -1
  2. angr/ailment/__init__.py +81 -0
  3. angr/ailment/block.py +81 -0
  4. angr/ailment/block_walker.py +845 -0
  5. angr/ailment/constant.py +3 -0
  6. angr/ailment/converter_common.py +11 -0
  7. angr/ailment/converter_pcode.py +623 -0
  8. angr/ailment/converter_vex.py +798 -0
  9. angr/ailment/expression.py +1639 -0
  10. angr/ailment/manager.py +33 -0
  11. angr/ailment/statement.py +978 -0
  12. angr/ailment/tagged_object.py +61 -0
  13. angr/ailment/utils.py +114 -0
  14. angr/analyses/calling_convention/calling_convention.py +6 -2
  15. angr/analyses/decompiler/ail_simplifier.py +5 -5
  16. angr/analyses/decompiler/block_io_finder.py +4 -4
  17. angr/analyses/decompiler/block_similarity.py +2 -2
  18. angr/analyses/decompiler/block_simplifier.py +4 -4
  19. angr/analyses/decompiler/callsite_maker.py +2 -2
  20. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  21. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
  22. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +1 -1
  23. angr/analyses/decompiler/clinic.py +1 -1
  24. angr/analyses/decompiler/condition_processor.py +1 -1
  25. angr/analyses/decompiler/counters/boolean_counter.py +4 -4
  26. angr/analyses/decompiler/counters/call_counter.py +4 -4
  27. angr/analyses/decompiler/counters/expression_counters.py +5 -5
  28. angr/analyses/decompiler/counters/seq_cf_structure_counter.py +1 -1
  29. angr/analyses/decompiler/decompiler.py +5 -3
  30. angr/analyses/decompiler/dephication/dephication_base.py +12 -1
  31. angr/analyses/decompiler/dephication/graph_dephication.py +12 -5
  32. angr/analyses/decompiler/dephication/graph_rewriting.py +6 -10
  33. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +109 -72
  34. angr/analyses/decompiler/dephication/rewriting_engine.py +32 -9
  35. angr/analyses/decompiler/dephication/seqnode_dephication.py +32 -10
  36. angr/analyses/decompiler/empty_node_remover.py +2 -2
  37. angr/analyses/decompiler/expression_narrower.py +6 -6
  38. angr/analyses/decompiler/goto_manager.py +2 -2
  39. angr/analyses/decompiler/jump_target_collector.py +1 -1
  40. angr/analyses/decompiler/label_collector.py +1 -1
  41. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +25 -25
  42. angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +1 -1
  43. angr/analyses/decompiler/optimization_passes/code_motion.py +2 -2
  44. angr/analyses/decompiler/optimization_passes/condition_constprop.py +3 -3
  45. angr/analyses/decompiler/optimization_passes/const_derefs.py +3 -3
  46. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +4 -4
  47. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +2 -2
  48. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +3 -3
  49. angr/analyses/decompiler/optimization_passes/div_simplifier.py +1 -1
  50. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  51. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +4 -4
  52. angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +1 -1
  53. angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +4 -4
  54. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +3 -3
  55. angr/analyses/decompiler/optimization_passes/engine_base.py +1 -1
  56. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +3 -3
  57. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
  58. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +2 -2
  59. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +3 -3
  60. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
  61. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +4 -4
  62. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +1 -1
  63. angr/analyses/decompiler/optimization_passes/optimization_pass.py +25 -1
  64. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +1 -1
  65. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +1 -1
  66. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -2
  67. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +4 -4
  68. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +2 -2
  69. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
  70. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +3 -3
  71. angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +3 -3
  72. angr/analyses/decompiler/optimization_passes/tag_slicer.py +1 -1
  73. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -1
  74. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +1 -1
  75. angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +1 -1
  76. angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +1 -1
  77. angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +1 -1
  78. angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +1 -1
  79. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +1 -1
  80. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +1 -1
  81. angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +1 -1
  82. angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +1 -1
  83. angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +1 -1
  84. angr/analyses/decompiler/peephole_optimizations/base.py +3 -3
  85. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +1 -1
  86. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +1 -1
  87. angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +1 -1
  88. angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +1 -1
  89. angr/analyses/decompiler/peephole_optimizations/bswap.py +2 -2
  90. angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +2 -2
  91. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +2 -2
  92. angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +1 -1
  93. angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +2 -2
  94. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -1
  95. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  96. angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +1 -1
  97. angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +1 -1
  98. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
  99. angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +1 -1
  100. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +2 -2
  101. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +2 -2
  102. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +2 -2
  103. angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +1 -1
  104. angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +1 -1
  105. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +1 -1
  106. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +2 -2
  107. angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +2 -2
  108. angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +1 -1
  109. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +1 -1
  110. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +1 -1
  111. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +1 -1
  112. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +1 -1
  113. angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +1 -1
  114. angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +1 -1
  115. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +1 -1
  116. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +1 -1
  117. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
  118. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +1 -1
  119. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +3 -3
  120. angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +1 -1
  121. angr/analyses/decompiler/peephole_optimizations/rol_ror.py +2 -2
  122. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -1
  123. angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +1 -1
  124. angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +1 -1
  125. angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +1 -1
  126. angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +1 -1
  127. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +2 -2
  128. angr/analyses/decompiler/peephole_optimizations/utils.py +1 -1
  129. angr/analyses/decompiler/redundant_label_remover.py +1 -1
  130. angr/analyses/decompiler/region_identifier.py +4 -4
  131. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -1
  132. angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +1 -1
  133. angr/analyses/decompiler/region_simplifiers/expr_folding.py +37 -8
  134. angr/analyses/decompiler/region_simplifiers/goto.py +1 -1
  135. angr/analyses/decompiler/region_simplifiers/if_.py +1 -1
  136. angr/analyses/decompiler/region_simplifiers/loop.py +1 -1
  137. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -1
  138. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +14 -2
  139. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +3 -3
  140. angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +1 -1
  141. angr/analyses/decompiler/return_maker.py +1 -1
  142. angr/analyses/decompiler/seq_to_blocks.py +1 -1
  143. angr/analyses/decompiler/sequence_walker.py +2 -2
  144. angr/analyses/decompiler/ssailification/rewriting.py +4 -4
  145. angr/analyses/decompiler/ssailification/rewriting_engine.py +4 -4
  146. angr/analyses/decompiler/ssailification/rewriting_state.py +3 -3
  147. angr/analyses/decompiler/ssailification/ssailification.py +2 -2
  148. angr/analyses/decompiler/ssailification/traversal.py +1 -1
  149. angr/analyses/decompiler/ssailification/traversal_engine.py +11 -2
  150. angr/analyses/decompiler/structured_codegen/c.py +3 -3
  151. angr/analyses/decompiler/structuring/dream.py +1 -1
  152. angr/analyses/decompiler/structuring/phoenix.py +3 -3
  153. angr/analyses/decompiler/structuring/structurer_base.py +1 -1
  154. angr/analyses/decompiler/structuring/structurer_nodes.py +1 -2
  155. angr/analyses/decompiler/utils.py +1 -1
  156. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  157. angr/analyses/deobfuscator/string_obf_opt_passes.py +3 -3
  158. angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +2 -2
  159. angr/analyses/propagator/propagator.py +1 -1
  160. angr/analyses/proximity_graph.py +2 -2
  161. angr/analyses/reaching_definitions/engine_ail.py +1 -1
  162. angr/analyses/reaching_definitions/reaching_definitions.py +1 -1
  163. angr/analyses/reaching_definitions/subject.py +1 -1
  164. angr/analyses/s_liveness.py +2 -2
  165. angr/analyses/s_propagator.py +3 -3
  166. angr/analyses/s_reaching_definitions/s_rda_model.py +1 -1
  167. angr/analyses/s_reaching_definitions/s_rda_view.py +3 -3
  168. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -3
  169. angr/analyses/variable_recovery/engine_ail.py +2 -2
  170. angr/analyses/variable_recovery/engine_base.py +1 -1
  171. angr/analyses/variable_recovery/variable_recovery_base.py +1 -1
  172. angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
  173. angr/engines/light/data.py +1 -1
  174. angr/engines/light/engine.py +1 -1
  175. angr/knowledge_plugins/key_definitions/atoms.py +1 -1
  176. angr/knowledge_plugins/propagations/prop_value.py +1 -1
  177. angr/knowledge_plugins/propagations/propagation_model.py +1 -1
  178. angr/knowledge_plugins/propagations/states.py +1 -1
  179. angr/knowledge_plugins/variables/variable_manager.py +1 -1
  180. angr/lib/angr_native.dylib +0 -0
  181. angr/rustylib.abi3.so +0 -0
  182. angr/utils/ail.py +4 -4
  183. angr/utils/endness.py +1 -1
  184. angr/utils/ssa/__init__.py +14 -4
  185. angr/utils/ssa/tmp_uses_collector.py +4 -4
  186. angr/utils/ssa/vvar_uses_collector.py +4 -4
  187. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/METADATA +6 -6
  188. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/RECORD +192 -180
  189. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/WHEEL +0 -0
  190. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/entry_points.txt +0 -0
  191. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/licenses/LICENSE +0 -0
  192. {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