angr 9.2.138__py3-none-manylinux2014_x86_64.whl → 9.2.140__py3-none-manylinux2014_x86_64.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/analyses/calling_convention/calling_convention.py +48 -21
- angr/analyses/calling_convention/fact_collector.py +59 -12
- angr/analyses/calling_convention/utils.py +2 -2
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +23 -4
- angr/analyses/decompiler/ail_simplifier.py +79 -53
- angr/analyses/decompiler/block_simplifier.py +0 -2
- angr/analyses/decompiler/callsite_maker.py +80 -14
- angr/analyses/decompiler/clinic.py +99 -80
- angr/analyses/decompiler/condition_processor.py +2 -2
- angr/analyses/decompiler/decompiler.py +19 -7
- angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +21 -12
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +17 -9
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +259 -108
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +28 -9
- angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
- angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
- angr/analyses/decompiler/structured_codegen/c.py +10 -3
- angr/analyses/decompiler/structuring/dream.py +28 -19
- angr/analyses/decompiler/structuring/phoenix.py +253 -89
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +121 -46
- angr/analyses/decompiler/structuring/structurer_nodes.py +6 -1
- angr/analyses/decompiler/utils.py +60 -1
- angr/analyses/deobfuscator/api_obf_finder.py +13 -5
- angr/analyses/deobfuscator/api_obf_type2_finder.py +166 -0
- angr/analyses/deobfuscator/string_obf_finder.py +105 -18
- angr/analyses/forward_analysis/forward_analysis.py +1 -1
- angr/analyses/propagator/top_checker_mixin.py +6 -6
- angr/analyses/reaching_definitions/__init__.py +2 -1
- angr/analyses/reaching_definitions/dep_graph.py +1 -12
- angr/analyses/reaching_definitions/engine_vex.py +36 -31
- angr/analyses/reaching_definitions/function_handler.py +15 -2
- angr/analyses/reaching_definitions/rd_state.py +1 -37
- angr/analyses/reaching_definitions/reaching_definitions.py +13 -24
- angr/analyses/s_propagator.py +129 -87
- angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
- angr/analyses/stack_pointer_tracker.py +36 -22
- angr/analyses/typehoon/simple_solver.py +45 -7
- angr/analyses/typehoon/typeconsts.py +18 -5
- angr/analyses/variable_recovery/engine_ail.py +1 -1
- angr/analyses/variable_recovery/engine_base.py +62 -67
- angr/analyses/variable_recovery/engine_vex.py +1 -1
- angr/analyses/variable_recovery/irsb_scanner.py +2 -2
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +81 -10
- angr/distributed/__init__.py +1 -1
- angr/engines/__init__.py +7 -8
- angr/engines/engine.py +3 -138
- angr/engines/failure.py +2 -2
- angr/engines/hook.py +2 -2
- angr/engines/light/engine.py +5 -10
- angr/engines/pcode/emulate.py +2 -2
- angr/engines/pcode/engine.py +2 -14
- angr/engines/pcode/lifter.py +2 -2
- angr/engines/procedure.py +2 -2
- angr/engines/soot/engine.py +2 -2
- angr/engines/soot/statements/switch.py +1 -1
- angr/engines/successors.py +123 -17
- angr/engines/syscall.py +2 -2
- angr/engines/unicorn.py +3 -3
- angr/engines/vex/heavy/heavy.py +3 -15
- angr/engines/vex/lifter.py +2 -2
- angr/engines/vex/light/light.py +2 -2
- angr/factory.py +4 -19
- angr/knowledge_plugins/cfg/cfg_model.py +3 -2
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/knowledge_plugins/labels.py +2 -2
- angr/knowledge_plugins/obfuscations.py +1 -0
- angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
- angr/sim_type.py +19 -17
- angr/state_plugins/plugin.py +19 -4
- angr/storage/memory_mixins/memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +10 -5
- angr/utils/ssa/__init__.py +119 -4
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/METADATA +6 -6
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/RECORD +100 -98
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/LICENSE +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/WHEEL +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/entry_points.txt +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/top_level.txt +0 -0
|
@@ -89,6 +89,8 @@ class Clinic(Analysis):
|
|
|
89
89
|
A Clinic deals with AILments.
|
|
90
90
|
"""
|
|
91
91
|
|
|
92
|
+
_ail_manager: ailment.Manager
|
|
93
|
+
|
|
92
94
|
def __init__(
|
|
93
95
|
self,
|
|
94
96
|
func,
|
|
@@ -109,7 +111,7 @@ class Clinic(Analysis):
|
|
|
109
111
|
cache: DecompilationCache | None = None,
|
|
110
112
|
mode: ClinicMode = ClinicMode.DECOMPILE,
|
|
111
113
|
sp_shift: int = 0,
|
|
112
|
-
inline_functions: set[Function] | None =
|
|
114
|
+
inline_functions: set[Function] | None = None,
|
|
113
115
|
inlined_counts: dict[int, int] | None = None,
|
|
114
116
|
inlining_parents: set[int] | None = None,
|
|
115
117
|
vvar_id_start: int = 0,
|
|
@@ -117,7 +119,6 @@ class Clinic(Analysis):
|
|
|
117
119
|
desired_variables: set[str] | None = None,
|
|
118
120
|
force_loop_single_exit: bool = True,
|
|
119
121
|
complete_successors: bool = False,
|
|
120
|
-
unsound_fix_abnormal_switches: bool = True,
|
|
121
122
|
):
|
|
122
123
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
123
124
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -131,11 +132,10 @@ class Clinic(Analysis):
|
|
|
131
132
|
self.arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimRegArg]] | None = None
|
|
132
133
|
self.variable_kb = variable_kb
|
|
133
134
|
self.externs: set[SimMemoryVariable] = set()
|
|
134
|
-
self.data_refs: dict[int,
|
|
135
|
+
self.data_refs: dict[int, list[DataRefDesc]] = {} # data address to data reference description
|
|
135
136
|
self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
|
|
136
137
|
|
|
137
138
|
self._func_graph: networkx.DiGraph | None = None
|
|
138
|
-
self._ail_manager = None
|
|
139
139
|
self._blocks_by_addr_and_size = {}
|
|
140
140
|
self.entry_node_addr: tuple[int, int | None] = self.function.addr, None
|
|
141
141
|
|
|
@@ -149,7 +149,6 @@ class Clinic(Analysis):
|
|
|
149
149
|
self._must_struct = must_struct
|
|
150
150
|
self._reset_variable_names = reset_variable_names
|
|
151
151
|
self._rewrite_ites_to_diamonds = rewrite_ites_to_diamonds
|
|
152
|
-
self._unsound_fix_abnormal_switches = unsound_fix_abnormal_switches
|
|
153
152
|
self.reaching_definitions: ReachingDefinitionsAnalysis | None = None
|
|
154
153
|
self._cache = cache
|
|
155
154
|
self._mode = mode
|
|
@@ -159,7 +158,7 @@ class Clinic(Analysis):
|
|
|
159
158
|
# inlining help
|
|
160
159
|
self._sp_shift = sp_shift
|
|
161
160
|
self._max_stack_depth = 0
|
|
162
|
-
self._inline_functions = inline_functions
|
|
161
|
+
self._inline_functions = inline_functions if inline_functions else set()
|
|
163
162
|
self._inlined_counts = {} if inlined_counts is None else inlined_counts
|
|
164
163
|
self._inlining_parents = inlining_parents or ()
|
|
165
164
|
self._desired_variables = desired_variables
|
|
@@ -167,6 +166,7 @@ class Clinic(Analysis):
|
|
|
167
166
|
self._complete_successors = complete_successors
|
|
168
167
|
|
|
169
168
|
self._register_save_areas_removed: bool = False
|
|
169
|
+
self.edges_to_remove: list[tuple[tuple[int, int | None], tuple[int, int | None]]] = []
|
|
170
170
|
|
|
171
171
|
self._new_block_addrs = set()
|
|
172
172
|
|
|
@@ -200,7 +200,7 @@ class Clinic(Analysis):
|
|
|
200
200
|
"""
|
|
201
201
|
|
|
202
202
|
try:
|
|
203
|
-
return self._blocks_by_addr_and_size[(addr, size)]
|
|
203
|
+
return self._blocks_by_addr_and_size[(addr, size)] if self._blocks_by_addr_and_size is not None else None
|
|
204
204
|
except KeyError:
|
|
205
205
|
return None
|
|
206
206
|
|
|
@@ -209,6 +209,7 @@ class Clinic(Analysis):
|
|
|
209
209
|
|
|
210
210
|
:return:
|
|
211
211
|
"""
|
|
212
|
+
assert self.graph is not None
|
|
212
213
|
|
|
213
214
|
s = ""
|
|
214
215
|
|
|
@@ -297,6 +298,8 @@ class Clinic(Analysis):
|
|
|
297
298
|
return ail_graph
|
|
298
299
|
|
|
299
300
|
def _slice_variables(self, ail_graph):
|
|
301
|
+
assert self.variable_kb is not None
|
|
302
|
+
|
|
300
303
|
nodes_index = {(n.addr, n.idx): n for n in ail_graph.nodes()}
|
|
301
304
|
|
|
302
305
|
vfm = self.variable_kb.variables.function_managers[self.function.addr]
|
|
@@ -344,7 +347,7 @@ class Clinic(Analysis):
|
|
|
344
347
|
optimization_passes=[StackCanarySimplifier],
|
|
345
348
|
sp_shift=self._max_stack_depth,
|
|
346
349
|
vvar_id_start=self.vvar_id_start,
|
|
347
|
-
fail_fast=self._fail_fast,
|
|
350
|
+
fail_fast=self._fail_fast, # type: ignore
|
|
348
351
|
)
|
|
349
352
|
self.vvar_id_start = callee_clinic.vvar_id_start + 1
|
|
350
353
|
self._max_stack_depth = callee_clinic._max_stack_depth
|
|
@@ -490,9 +493,7 @@ class Clinic(Analysis):
|
|
|
490
493
|
# we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
|
|
491
494
|
# before they are recognized as stack arguments.
|
|
492
495
|
self._update_progress(38.0, text="Simplifying blocks 1")
|
|
493
|
-
ail_graph = self._simplify_blocks(
|
|
494
|
-
ail_graph, stack_pointer_tracker=spt, remove_dead_memdefs=False, cache=block_simplification_cache
|
|
495
|
-
)
|
|
496
|
+
ail_graph = self._simplify_blocks(ail_graph, stack_pointer_tracker=spt, cache=block_simplification_cache)
|
|
496
497
|
self._rewrite_alloca(ail_graph)
|
|
497
498
|
|
|
498
499
|
# Run simplification passes
|
|
@@ -515,9 +516,7 @@ class Clinic(Analysis):
|
|
|
515
516
|
# Run simplification passes again. there might be more chances for peephole optimizations after function-level
|
|
516
517
|
# simplification
|
|
517
518
|
self._update_progress(48.0, text="Simplifying blocks 2")
|
|
518
|
-
ail_graph = self._simplify_blocks(
|
|
519
|
-
ail_graph, stack_pointer_tracker=spt, remove_dead_memdefs=False, cache=block_simplification_cache
|
|
520
|
-
)
|
|
519
|
+
ail_graph = self._simplify_blocks(ail_graph, stack_pointer_tracker=spt, cache=block_simplification_cache)
|
|
521
520
|
|
|
522
521
|
# rewrite (qualified) stack variables into SSA form
|
|
523
522
|
ail_graph = self._transform_to_ssa_level1(ail_graph, func_args)
|
|
@@ -557,7 +556,6 @@ class Clinic(Analysis):
|
|
|
557
556
|
self._update_progress(60.0, text="Simplifying blocks 3")
|
|
558
557
|
ail_graph = self._simplify_blocks(
|
|
559
558
|
ail_graph,
|
|
560
|
-
remove_dead_memdefs=self._remove_dead_memdefs,
|
|
561
559
|
stack_pointer_tracker=spt,
|
|
562
560
|
cache=block_simplification_cache,
|
|
563
561
|
)
|
|
@@ -581,7 +579,6 @@ class Clinic(Analysis):
|
|
|
581
579
|
self._update_progress(75.0, text="Simplifying blocks 4")
|
|
582
580
|
ail_graph = self._simplify_blocks(
|
|
583
581
|
ail_graph,
|
|
584
|
-
remove_dead_memdefs=self._remove_dead_memdefs,
|
|
585
582
|
stack_pointer_tracker=spt,
|
|
586
583
|
cache=block_simplification_cache,
|
|
587
584
|
)
|
|
@@ -624,6 +621,7 @@ class Clinic(Analysis):
|
|
|
624
621
|
|
|
625
622
|
# remove empty nodes from the graph
|
|
626
623
|
ail_graph = self.remove_empty_nodes(ail_graph)
|
|
624
|
+
# note that there are still edges to remove before we can structure this graph!
|
|
627
625
|
|
|
628
626
|
self.arg_list = arg_list
|
|
629
627
|
self.arg_vvars = arg_vvars
|
|
@@ -694,9 +692,7 @@ class Clinic(Analysis):
|
|
|
694
692
|
# we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
|
|
695
693
|
# before they are recognized as stack arguments.
|
|
696
694
|
self._update_progress(35.0, text="Simplifying blocks 1")
|
|
697
|
-
ail_graph = self._simplify_blocks(
|
|
698
|
-
ail_graph, stack_pointer_tracker=spt, remove_dead_memdefs=False, cache=block_simplification_cache
|
|
699
|
-
)
|
|
695
|
+
ail_graph = self._simplify_blocks(ail_graph, stack_pointer_tracker=spt, cache=block_simplification_cache)
|
|
700
696
|
|
|
701
697
|
# Simplify the entire function for the first time
|
|
702
698
|
self._update_progress(45.0, text="Simplifying function 1")
|
|
@@ -808,7 +804,7 @@ class Clinic(Analysis):
|
|
|
808
804
|
|
|
809
805
|
# case 2: the callee is a SimProcedure
|
|
810
806
|
if target_func.is_simprocedure:
|
|
811
|
-
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast)
|
|
807
|
+
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast) # type: ignore
|
|
812
808
|
if cc.cc is not None and cc.prototype is not None:
|
|
813
809
|
target_func.calling_convention = cc.cc
|
|
814
810
|
target_func.prototype = cc.prototype
|
|
@@ -816,7 +812,7 @@ class Clinic(Analysis):
|
|
|
816
812
|
|
|
817
813
|
# case 3: the callee is a PLT function
|
|
818
814
|
if target_func.is_plt:
|
|
819
|
-
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast)
|
|
815
|
+
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast) # type: ignore
|
|
820
816
|
if cc.cc is not None and cc.prototype is not None:
|
|
821
817
|
target_func.calling_convention = cc.cc
|
|
822
818
|
target_func.prototype = cc.prototype
|
|
@@ -886,7 +882,7 @@ class Clinic(Analysis):
|
|
|
886
882
|
# finally, recover the calling convention of the current function
|
|
887
883
|
if self.function.prototype is None or self.function.calling_convention is None:
|
|
888
884
|
self.project.analyses.CompleteCallingConventions(
|
|
889
|
-
fail_fast=self._fail_fast,
|
|
885
|
+
fail_fast=self._fail_fast, # type: ignore
|
|
890
886
|
recover_variables=True,
|
|
891
887
|
prioritize_func_addrs=[self.function.addr],
|
|
892
888
|
skip_other_funcs=True,
|
|
@@ -1101,7 +1097,6 @@ class Clinic(Analysis):
|
|
|
1101
1097
|
def _simplify_blocks(
|
|
1102
1098
|
self,
|
|
1103
1099
|
ail_graph: networkx.DiGraph,
|
|
1104
|
-
remove_dead_memdefs=False,
|
|
1105
1100
|
stack_pointer_tracker=None,
|
|
1106
1101
|
cache: dict[ailment.Block, NamedTuple] | None = None,
|
|
1107
1102
|
):
|
|
@@ -1120,7 +1115,6 @@ class Clinic(Analysis):
|
|
|
1120
1115
|
for ail_block in ail_graph.nodes():
|
|
1121
1116
|
simplified = self._simplify_block(
|
|
1122
1117
|
ail_block,
|
|
1123
|
-
remove_dead_memdefs=remove_dead_memdefs,
|
|
1124
1118
|
stack_pointer_tracker=stack_pointer_tracker,
|
|
1125
1119
|
cache=cache,
|
|
1126
1120
|
)
|
|
@@ -1138,7 +1132,7 @@ class Clinic(Analysis):
|
|
|
1138
1132
|
|
|
1139
1133
|
return ail_graph
|
|
1140
1134
|
|
|
1141
|
-
def _simplify_block(self, ail_block,
|
|
1135
|
+
def _simplify_block(self, ail_block, stack_pointer_tracker=None, cache=None):
|
|
1142
1136
|
"""
|
|
1143
1137
|
Simplify a single AIL block.
|
|
1144
1138
|
|
|
@@ -1149,8 +1143,9 @@ class Clinic(Analysis):
|
|
|
1149
1143
|
|
|
1150
1144
|
cached_rd, cached_prop = None, None
|
|
1151
1145
|
cache_item = None
|
|
1146
|
+
cache_key = ail_block.addr, ail_block.idx
|
|
1152
1147
|
if cache:
|
|
1153
|
-
cache_item = cache.get(
|
|
1148
|
+
cache_item = cache.get(cache_key, None)
|
|
1154
1149
|
if cache_item:
|
|
1155
1150
|
# cache hit
|
|
1156
1151
|
cached_rd = cache_item.rd
|
|
@@ -1160,7 +1155,6 @@ class Clinic(Analysis):
|
|
|
1160
1155
|
ail_block,
|
|
1161
1156
|
self.function.addr,
|
|
1162
1157
|
fail_fast=self._fail_fast,
|
|
1163
|
-
remove_dead_memdefs=remove_dead_memdefs,
|
|
1164
1158
|
stack_pointer_tracker=stack_pointer_tracker,
|
|
1165
1159
|
peephole_optimizations=self.peephole_optimizations,
|
|
1166
1160
|
cached_reaching_definitions=cached_rd,
|
|
@@ -1169,8 +1163,8 @@ class Clinic(Analysis):
|
|
|
1169
1163
|
# update the cache
|
|
1170
1164
|
if cache is not None:
|
|
1171
1165
|
if cache_item:
|
|
1172
|
-
del cache[
|
|
1173
|
-
cache[
|
|
1166
|
+
del cache[cache_key]
|
|
1167
|
+
cache[cache_key] = BlockCache(simp._reaching_definitions, simp._propagator)
|
|
1174
1168
|
return simp.result_block
|
|
1175
1169
|
|
|
1176
1170
|
@timethis
|
|
@@ -1807,7 +1801,7 @@ class Clinic(Analysis):
|
|
|
1807
1801
|
else:
|
|
1808
1802
|
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.operand)
|
|
1809
1803
|
|
|
1810
|
-
elif type(expr)
|
|
1804
|
+
elif type(expr) in {ailment.Expr.Convert, ailment.Expr.Reinterpret}:
|
|
1811
1805
|
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.operand)
|
|
1812
1806
|
|
|
1813
1807
|
elif type(expr) is ailment.Expr.ITE:
|
|
@@ -1828,7 +1822,7 @@ class Clinic(Analysis):
|
|
|
1828
1822
|
expr.variable = var
|
|
1829
1823
|
expr.variable_offset = offset
|
|
1830
1824
|
|
|
1831
|
-
elif isinstance(expr, ailment.Expr.Const):
|
|
1825
|
+
elif isinstance(expr, ailment.Expr.Const) and expr.is_int:
|
|
1832
1826
|
# custom string?
|
|
1833
1827
|
if hasattr(expr, "custom_string") and expr.custom_string is True:
|
|
1834
1828
|
s = self.kb.custom_strings[expr.value]
|
|
@@ -1873,6 +1867,7 @@ class Clinic(Analysis):
|
|
|
1873
1867
|
def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
|
|
1874
1868
|
if blocks_by_addr_and_size is None:
|
|
1875
1869
|
blocks_by_addr_and_size = self._blocks_by_addr_and_size
|
|
1870
|
+
assert blocks_by_addr_and_size is not None
|
|
1876
1871
|
|
|
1877
1872
|
graph = networkx.DiGraph()
|
|
1878
1873
|
|
|
@@ -1947,8 +1942,9 @@ class Clinic(Analysis):
|
|
|
1947
1942
|
break
|
|
1948
1943
|
if ite_expr_stmt_idx is None:
|
|
1949
1944
|
return None
|
|
1945
|
+
assert ite_expr_stmt is not None
|
|
1950
1946
|
|
|
1951
|
-
ite_expr: ailment.Expr.ITE = ite_expr_stmt.src
|
|
1947
|
+
ite_expr: ailment.Expr.ITE = ite_expr_stmt.src # type: ignore
|
|
1952
1948
|
new_head_ail.statements = new_head_ail.statements[:ite_expr_stmt_idx]
|
|
1953
1949
|
# build the conditional jump
|
|
1954
1950
|
true_block_addr = ite_ins_addr + 1
|
|
@@ -1976,6 +1972,7 @@ class Clinic(Analysis):
|
|
|
1976
1972
|
break
|
|
1977
1973
|
if ite_expr_stmt_idx is None:
|
|
1978
1974
|
return None
|
|
1975
|
+
assert ite_expr_stmt is not None
|
|
1979
1976
|
|
|
1980
1977
|
true_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
|
|
1981
1978
|
ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iftrue, **ite_expr_stmt.tags
|
|
@@ -1995,6 +1992,7 @@ class Clinic(Analysis):
|
|
|
1995
1992
|
break
|
|
1996
1993
|
if ite_expr_stmt_idx is None:
|
|
1997
1994
|
return None
|
|
1995
|
+
assert ite_expr_stmt is not None
|
|
1998
1996
|
|
|
1999
1997
|
false_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
|
|
2000
1998
|
ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iffalse, **ite_expr_stmt.tags
|
|
@@ -2002,8 +2000,8 @@ class Clinic(Analysis):
|
|
|
2002
2000
|
|
|
2003
2001
|
original_block = next(iter(b for b in ail_graph if b.addr == block_addr))
|
|
2004
2002
|
|
|
2005
|
-
original_block_in_edges = list(ail_graph.in_edges(original_block))
|
|
2006
|
-
original_block_out_edges = list(ail_graph.out_edges(original_block))
|
|
2003
|
+
original_block_in_edges = list(ail_graph.in_edges(original_block, data=True))
|
|
2004
|
+
original_block_out_edges = list(ail_graph.out_edges(original_block, data=True))
|
|
2007
2005
|
|
|
2008
2006
|
# build the target block if the target block does not exist in the current function
|
|
2009
2007
|
end_block_addr = ite_ins_addr + ite_insn_size
|
|
@@ -2040,19 +2038,19 @@ class Clinic(Analysis):
|
|
|
2040
2038
|
|
|
2041
2039
|
if end_block_ail not in ail_graph:
|
|
2042
2040
|
# newly created. add it and the necessary edges into the graph
|
|
2043
|
-
for _, dst in original_block_out_edges:
|
|
2041
|
+
for _, dst, data in original_block_out_edges:
|
|
2044
2042
|
if dst is original_block:
|
|
2045
|
-
ail_graph.add_edge(end_block_ail, new_head_ail)
|
|
2043
|
+
ail_graph.add_edge(end_block_ail, new_head_ail, **data)
|
|
2046
2044
|
else:
|
|
2047
|
-
ail_graph.add_edge(end_block_ail, dst)
|
|
2045
|
+
ail_graph.add_edge(end_block_ail, dst, **data)
|
|
2048
2046
|
|
|
2049
2047
|
# in edges
|
|
2050
|
-
for src, _ in original_block_in_edges:
|
|
2048
|
+
for src, _, data in original_block_in_edges:
|
|
2051
2049
|
if src is original_block:
|
|
2052
2050
|
# loop
|
|
2053
|
-
ail_graph.add_edge(end_block_ail, new_head_ail)
|
|
2051
|
+
ail_graph.add_edge(end_block_ail, new_head_ail, **data)
|
|
2054
2052
|
else:
|
|
2055
|
-
ail_graph.add_edge(src, new_head_ail)
|
|
2053
|
+
ail_graph.add_edge(src, new_head_ail, **data)
|
|
2056
2054
|
|
|
2057
2055
|
# triangle
|
|
2058
2056
|
ail_graph.add_edge(new_head_ail, true_block_ail)
|
|
@@ -2115,49 +2113,60 @@ class Clinic(Analysis):
|
|
|
2115
2113
|
# the overlapped instructions and add an unconditional jump so that it jumps to 0x41da9d.
|
|
2116
2114
|
# this is the most common case created by jump threading optimization in compilers. it's easy to handle.
|
|
2117
2115
|
|
|
2118
|
-
# Case 2: the intended head and the other heads do not share the same suffix of instructions. in this
|
|
2119
|
-
#
|
|
2120
|
-
#
|
|
2121
|
-
#
|
|
2116
|
+
# Case 2 & 3: the intended head and the other heads do not share the same suffix of instructions. in this
|
|
2117
|
+
# case, we have two choices:
|
|
2118
|
+
# Case 2: The intended head has two successors, but at least one unintended head has only one successor.
|
|
2119
|
+
# we cannot reliably convert the blocks into a properly structured switch-case construct. we will
|
|
2120
|
+
# last instruction of all other heads to jump to the cmp instruction in the intended head, but do
|
|
2121
|
+
# not remove any other instructions in these other heads. this is unsound, but is the best we can
|
|
2122
|
+
# do in this case.
|
|
2123
|
+
# Case 3: The intended head has only one successor (which is the indirect jump node). during structuring,
|
|
2124
|
+
# we expect it will be structured as a no-default-node switch-case construct. in this case, we
|
|
2125
|
+
# can simply remove the edges from all other heads to the jump node and only leave the edge from
|
|
2126
|
+
# the intended head to the jump node. we will see goto statements in the output, but this will
|
|
2127
|
+
# lead to correct structuring result.
|
|
2122
2128
|
|
|
2123
2129
|
overlaps = [self._get_overlapping_suffix_instructions(intended_head, head) for head in other_heads]
|
|
2124
2130
|
if overlaps and (overlap := min(overlaps)) > 0:
|
|
2125
2131
|
# Case 1
|
|
2126
2132
|
self._fix_abnormal_switch_case_heads_case1(ail_graph, candidate, intended_head, other_heads, overlap)
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
None,
|
|
2143
|
-
)
|
|
2144
|
-
intended_head_block = self.project.factory.block(
|
|
2145
|
-
intended_head.addr, size=intended_head.original_size
|
|
2133
|
+
elif ail_graph.out_degree[intended_head] == 2:
|
|
2134
|
+
# Case 2
|
|
2135
|
+
l.warning("Switch-case at %#x has multiple head nodes but cannot be fixed soundly.", candidate.addr)
|
|
2136
|
+
# find the comparison instruction in the intended head
|
|
2137
|
+
comparison_stmt = None
|
|
2138
|
+
if "cc_op" in self.project.arch.registers:
|
|
2139
|
+
comparison_stmt = next(
|
|
2140
|
+
iter(
|
|
2141
|
+
stmt
|
|
2142
|
+
for stmt in intended_head.statements
|
|
2143
|
+
if isinstance(stmt, ailment.Stmt.Assignment)
|
|
2144
|
+
and isinstance(stmt.dst, ailment.Expr.Register)
|
|
2145
|
+
and stmt.dst.reg_offset == self.project.arch.registers["cc_op"][0]
|
|
2146
|
+
),
|
|
2147
|
+
None,
|
|
2146
2148
|
)
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
else:
|
|
2152
|
-
cmp_rpos = min(len(intended_head_block.instruction_addrs), 2)
|
|
2153
|
-
self._fix_abnormal_switch_case_heads_case2(
|
|
2154
|
-
ail_graph,
|
|
2155
|
-
candidate,
|
|
2156
|
-
intended_head,
|
|
2157
|
-
other_heads,
|
|
2158
|
-
intended_head_split_insns=cmp_rpos,
|
|
2159
|
-
other_head_split_insns=0,
|
|
2149
|
+
intended_head_block = self.project.factory.block(intended_head.addr, size=intended_head.original_size)
|
|
2150
|
+
if comparison_stmt is not None:
|
|
2151
|
+
cmp_rpos = len(intended_head_block.instruction_addrs) - intended_head_block.instruction_addrs.index(
|
|
2152
|
+
comparison_stmt.ins_addr
|
|
2160
2153
|
)
|
|
2154
|
+
else:
|
|
2155
|
+
cmp_rpos = min(len(intended_head_block.instruction_addrs), 2)
|
|
2156
|
+
self._fix_abnormal_switch_case_heads_case2(
|
|
2157
|
+
ail_graph,
|
|
2158
|
+
candidate,
|
|
2159
|
+
intended_head,
|
|
2160
|
+
other_heads,
|
|
2161
|
+
intended_head_split_insns=cmp_rpos,
|
|
2162
|
+
other_head_split_insns=0,
|
|
2163
|
+
)
|
|
2164
|
+
else:
|
|
2165
|
+
# Case 3
|
|
2166
|
+
self._fix_abnormal_switch_case_heads_case3(
|
|
2167
|
+
candidate,
|
|
2168
|
+
other_heads,
|
|
2169
|
+
)
|
|
2161
2170
|
|
|
2162
2171
|
def _get_overlapping_suffix_instructions(self, ailblock_0: ailment.Block, ailblock_1: ailment.Block) -> int:
|
|
2163
2172
|
# we first compare their ending conditional jumps
|
|
@@ -2366,6 +2375,16 @@ class Clinic(Analysis):
|
|
|
2366
2375
|
# it should be going to the default node. ignore it
|
|
2367
2376
|
pass
|
|
2368
2377
|
|
|
2378
|
+
def _fix_abnormal_switch_case_heads_case3(
|
|
2379
|
+
self, indirect_jump_node: ailment.Block, other_heads: list[ailment.Block]
|
|
2380
|
+
) -> None:
|
|
2381
|
+
# remove all edges from other_heads to the indirect jump node
|
|
2382
|
+
for other_head in other_heads:
|
|
2383
|
+
# delay the edge removal so that we don't mess up the SSA analysis
|
|
2384
|
+
self.edges_to_remove.append(
|
|
2385
|
+
((other_head.addr, other_head.idx), (indirect_jump_node.addr, indirect_jump_node.idx))
|
|
2386
|
+
)
|
|
2387
|
+
|
|
2369
2388
|
@staticmethod
|
|
2370
2389
|
def _remove_redundant_jump_blocks(ail_graph):
|
|
2371
2390
|
def first_conditional_jump(block: ailment.Block) -> ailment.Stmt.ConditionalJump | None:
|
|
@@ -2466,7 +2485,7 @@ class Clinic(Analysis):
|
|
|
2466
2485
|
expr_idx: int,
|
|
2467
2486
|
expr: ailment.expression.Expression,
|
|
2468
2487
|
stmt_idx: int,
|
|
2469
|
-
stmt: ailment.statement.Statement,
|
|
2488
|
+
stmt: ailment.statement.Statement | None,
|
|
2470
2489
|
block: ailment.Block | None,
|
|
2471
2490
|
):
|
|
2472
2491
|
if expr is None:
|
|
@@ -2500,7 +2519,7 @@ class Clinic(Analysis):
|
|
|
2500
2519
|
expr: ailment.expression.Const,
|
|
2501
2520
|
stmt_idx: int,
|
|
2502
2521
|
stmt: ailment.statement.Statement,
|
|
2503
|
-
block: ailment.Block
|
|
2522
|
+
block: ailment.Block,
|
|
2504
2523
|
):
|
|
2505
2524
|
if isinstance(expr.value, int) and hasattr(expr, "ins_addr"):
|
|
2506
2525
|
data_refs[block.addr].append(
|
|
@@ -2518,7 +2537,7 @@ class Clinic(Analysis):
|
|
|
2518
2537
|
expr: ailment.expression.Load,
|
|
2519
2538
|
stmt_idx: int,
|
|
2520
2539
|
stmt: ailment.statement.Statement,
|
|
2521
|
-
block: ailment.Block
|
|
2540
|
+
block: ailment.Block,
|
|
2522
2541
|
):
|
|
2523
2542
|
if isinstance(expr.addr, ailment.expression.Const):
|
|
2524
2543
|
addr = expr.addr
|
|
@@ -2548,7 +2567,7 @@ class Clinic(Analysis):
|
|
|
2548
2567
|
|
|
2549
2568
|
return ailment.AILBlockWalker._handle_Load(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
2550
2569
|
|
|
2551
|
-
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block
|
|
2570
|
+
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block):
|
|
2552
2571
|
if isinstance(stmt.addr, ailment.expression.Const):
|
|
2553
2572
|
addr = stmt.addr
|
|
2554
2573
|
if isinstance(addr.value, int) and hasattr(addr, "ins_addr"):
|
|
@@ -18,7 +18,7 @@ from angr.utils import is_pyinstaller
|
|
|
18
18
|
from angr.utils.graph import dominates, inverted_idoms
|
|
19
19
|
from angr.block import Block, BlockNode
|
|
20
20
|
from angr.errors import AngrRuntimeError
|
|
21
|
-
from .peephole_optimizations import InvertNegatedLogicalConjunctionsAndDisjunctions
|
|
21
|
+
from .peephole_optimizations import InvertNegatedLogicalConjunctionsAndDisjunctions, RemoveRedundantNots
|
|
22
22
|
from .structuring.structurer_nodes import (
|
|
23
23
|
MultiNode,
|
|
24
24
|
EmptyBlockNotice,
|
|
@@ -231,7 +231,7 @@ class ConditionProcessor:
|
|
|
231
231
|
self._ast2annotations = {}
|
|
232
232
|
|
|
233
233
|
self._peephole_expr_optimizations = [
|
|
234
|
-
cls(None, None, None) for cls in [InvertNegatedLogicalConjunctionsAndDisjunctions]
|
|
234
|
+
cls(None, None, None) for cls in [InvertNegatedLogicalConjunctionsAndDisjunctions, RemoveRedundantNots]
|
|
235
235
|
]
|
|
236
236
|
|
|
237
237
|
def clear(self):
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import logging
|
|
4
4
|
from collections import defaultdict
|
|
5
|
-
from typing import Optional, Union, Any, TYPE_CHECKING
|
|
6
5
|
from collections.abc import Iterable
|
|
6
|
+
from typing import Optional, Union, Any, TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
import networkx
|
|
9
9
|
from cle import SymbolType
|
|
@@ -15,6 +15,7 @@ from angr.knowledge_base import KnowledgeBase
|
|
|
15
15
|
from angr.sim_variable import SimMemoryVariable, SimRegisterVariable, SimStackVariable
|
|
16
16
|
from angr.utils import timethis
|
|
17
17
|
from angr.analyses import Analysis, AnalysesHub
|
|
18
|
+
from .structured_codegen.c import CStructuredCodeGenerator
|
|
18
19
|
from .structuring import RecursiveStructurer, PhoenixStructurer, DEFAULT_STRUCTURER
|
|
19
20
|
from .region_identifier import RegionIdentifier
|
|
20
21
|
from .optimization_passes.optimization_pass import OptimizationPassStage
|
|
@@ -22,7 +23,7 @@ from .ailgraph_walker import AILGraphWalker
|
|
|
22
23
|
from .condition_processor import ConditionProcessor
|
|
23
24
|
from .decompilation_options import DecompilationOption
|
|
24
25
|
from .decompilation_cache import DecompilationCache
|
|
25
|
-
from .utils import remove_labels
|
|
26
|
+
from .utils import remove_labels, remove_edges_in_ailgraph
|
|
26
27
|
from .sequence_walker import SequenceWalker
|
|
27
28
|
from .structuring.structurer_nodes import SequenceNode
|
|
28
29
|
from .presets import DECOMPILATION_PRESETS, DecompilationPreset
|
|
@@ -30,7 +31,6 @@ from .presets import DECOMPILATION_PRESETS, DecompilationPreset
|
|
|
30
31
|
if TYPE_CHECKING:
|
|
31
32
|
from angr.knowledge_plugins.cfg.cfg_model import CFGModel
|
|
32
33
|
from .peephole_optimizations import PeepholeOptimizationExprBase, PeepholeOptimizationStmtBase
|
|
33
|
-
from .structured_codegen.c import CStructuredCodeGenerator
|
|
34
34
|
|
|
35
35
|
l = logging.getLogger(name=__name__)
|
|
36
36
|
|
|
@@ -157,6 +157,8 @@ class Decompiler(Analysis):
|
|
|
157
157
|
self.kb.decompilations[(self.func.addr, self._flavor)].errors.append(error.format())
|
|
158
158
|
|
|
159
159
|
def _can_use_decompilation_cache(self, cache: DecompilationCache) -> bool:
|
|
160
|
+
if self._cache_parameters is None or cache.parameters is None:
|
|
161
|
+
return False
|
|
160
162
|
a, b = self._cache_parameters, cache.parameters
|
|
161
163
|
id_checks = {"cfg", "variable_kb"}
|
|
162
164
|
return all(a[k] is b[k] if k in id_checks else a[k] == b[k] for k in self._cache_parameters)
|
|
@@ -201,7 +203,7 @@ class Decompiler(Analysis):
|
|
|
201
203
|
|
|
202
204
|
variable_kb = self._variable_kb
|
|
203
205
|
# fall back to old codegen
|
|
204
|
-
if variable_kb is None and old_codegen is not None:
|
|
206
|
+
if variable_kb is None and old_codegen is not None and isinstance(old_codegen, CStructuredCodeGenerator):
|
|
205
207
|
variable_kb = old_codegen._variable_kb
|
|
206
208
|
|
|
207
209
|
if variable_kb is None:
|
|
@@ -223,7 +225,8 @@ class Decompiler(Analysis):
|
|
|
223
225
|
fold_callexprs_into_conditions = True
|
|
224
226
|
|
|
225
227
|
cache = DecompilationCache(self.func.addr)
|
|
226
|
-
|
|
228
|
+
if self._cache_parameters is not None:
|
|
229
|
+
cache.parameters = self._cache_parameters
|
|
227
230
|
cache.ite_exprs = ite_exprs
|
|
228
231
|
cache.binop_operators = binop_operators
|
|
229
232
|
|
|
@@ -288,14 +291,22 @@ class Decompiler(Analysis):
|
|
|
288
291
|
)
|
|
289
292
|
ri = self._recover_regions(clinic.graph, cond_proc, update_graph=not delay_graph_updates)
|
|
290
293
|
|
|
294
|
+
self._update_progress(73.0, text="Running region-simplification passes")
|
|
295
|
+
|
|
291
296
|
# run optimizations that may require re-RegionIdentification
|
|
292
297
|
clinic.graph, ri = self._run_region_simplification_passes(
|
|
293
298
|
clinic.graph,
|
|
294
299
|
ri,
|
|
295
300
|
clinic.reaching_definitions,
|
|
296
301
|
ite_exprs=ite_exprs,
|
|
302
|
+
arg_vvars=set(clinic.arg_vvars),
|
|
303
|
+
edges_to_remove=clinic.edges_to_remove,
|
|
297
304
|
)
|
|
298
305
|
|
|
306
|
+
# finally (no more graph-based simplifications will run in the future), we can remove the edges that should be
|
|
307
|
+
# removed!
|
|
308
|
+
remove_edges_in_ailgraph(clinic.graph, clinic.edges_to_remove)
|
|
309
|
+
|
|
299
310
|
# Rewrite the graph to remove phi expressions
|
|
300
311
|
# this is probably optional if we do not pretty-print clinic.graph
|
|
301
312
|
clinic.graph = self._transform_graph_from_ssa(clinic.graph)
|
|
@@ -323,9 +334,9 @@ class Decompiler(Analysis):
|
|
|
323
334
|
s = self.project.analyses.RegionSimplifier(
|
|
324
335
|
self.func,
|
|
325
336
|
rs.result,
|
|
337
|
+
arg_vvars=set(self.clinic.arg_vvars),
|
|
326
338
|
kb=self.kb,
|
|
327
339
|
fail_fast=self._fail_fast,
|
|
328
|
-
variable_kb=clinic.variable_kb,
|
|
329
340
|
**self.options_to_params(self.options_by_class["region_simplifier"]),
|
|
330
341
|
)
|
|
331
342
|
seq_node = s.result
|
|
@@ -437,7 +448,7 @@ class Decompiler(Analysis):
|
|
|
437
448
|
return ail_graph
|
|
438
449
|
|
|
439
450
|
@timethis
|
|
440
|
-
def _run_region_simplification_passes(self, ail_graph, ri, reaching_definitions, **kwargs):
|
|
451
|
+
def _run_region_simplification_passes(self, ail_graph, ri, reaching_definitions, arg_vvars: set[int], **kwargs):
|
|
441
452
|
"""
|
|
442
453
|
Runs optimizations that should be executed after a single region identification. This function will return
|
|
443
454
|
two items: the new RegionIdentifier object and the new AIL Graph, which should probably be written
|
|
@@ -481,6 +492,7 @@ class Decompiler(Analysis):
|
|
|
481
492
|
blocks_by_addr_and_idx=addr_and_idx_to_blocks,
|
|
482
493
|
graph=ail_graph,
|
|
483
494
|
variable_kb=self._variable_kb,
|
|
495
|
+
arg_vvars=arg_vvars,
|
|
484
496
|
region_identifier=ri,
|
|
485
497
|
reaching_definitions=reaching_definitions,
|
|
486
498
|
vvar_id_start=self.vvar_id_start,
|
|
@@ -15,6 +15,7 @@ from ailment.expression import (
|
|
|
15
15
|
ITE,
|
|
16
16
|
VEXCCallExpression,
|
|
17
17
|
DirtyExpression,
|
|
18
|
+
Reinterpret,
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
from angr.engines.light import SimEngineNostmtAIL
|
|
@@ -164,7 +165,7 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
164
165
|
return Load(expr.idx, new_addr, expr.size, expr.endness, guard=expr.guard, alt=expr.alt, **expr.tags)
|
|
165
166
|
return None
|
|
166
167
|
|
|
167
|
-
def _handle_expr_Convert(self, expr):
|
|
168
|
+
def _handle_expr_Convert(self, expr: Convert) -> Convert | None:
|
|
168
169
|
new_operand = self._expr(expr.operand)
|
|
169
170
|
if new_operand is not None:
|
|
170
171
|
return Convert(
|
|
@@ -180,6 +181,20 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
180
181
|
)
|
|
181
182
|
return None
|
|
182
183
|
|
|
184
|
+
def _handle_expr_Reinterpret(self, expr: Reinterpret) -> Reinterpret | None:
|
|
185
|
+
new_operand = self._expr(expr.operand)
|
|
186
|
+
if new_operand is not None:
|
|
187
|
+
return Reinterpret(
|
|
188
|
+
expr.idx,
|
|
189
|
+
expr.from_bits,
|
|
190
|
+
expr.from_type,
|
|
191
|
+
expr.to_bits,
|
|
192
|
+
expr.to_type,
|
|
193
|
+
new_operand,
|
|
194
|
+
**expr.tags,
|
|
195
|
+
)
|
|
196
|
+
return None
|
|
197
|
+
|
|
183
198
|
def _handle_expr_Const(self, expr):
|
|
184
199
|
return None
|
|
185
200
|
|
|
@@ -346,18 +361,12 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
346
361
|
)
|
|
347
362
|
return None
|
|
348
363
|
|
|
349
|
-
def _handle_expr_DirtyExpression(self, expr):
|
|
350
|
-
return None
|
|
351
|
-
|
|
352
364
|
def _handle_expr_MultiStatementExpression(self, expr):
|
|
353
365
|
return None
|
|
354
366
|
|
|
355
367
|
def _handle_expr_Register(self, expr):
|
|
356
368
|
return None
|
|
357
369
|
|
|
358
|
-
def _handle_expr_Reinterpret(self, expr):
|
|
359
|
-
return None
|
|
360
|
-
|
|
361
370
|
def _handle_expr_Tmp(self, expr):
|
|
362
371
|
return None
|
|
363
372
|
|
|
@@ -38,7 +38,7 @@ class ExprNarrowingInfo:
|
|
|
38
38
|
narrowable: bool,
|
|
39
39
|
to_size: int | None = None,
|
|
40
40
|
use_exprs: list[tuple[atoms.VirtualVariable, CodeLocation, tuple[str, tuple[Expression, ...]]]] | None = None,
|
|
41
|
-
phi_vars: set[
|
|
41
|
+
phi_vars: set[VirtualVariable] | None = None,
|
|
42
42
|
):
|
|
43
43
|
self.narrowable = narrowable
|
|
44
44
|
self.to_size = to_size
|