angr 9.2.139__py3-none-manylinux2014_x86_64.whl → 9.2.141__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 +136 -53
- angr/analyses/calling_convention/fact_collector.py +44 -18
- angr/analyses/calling_convention/utils.py +3 -1
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +11 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +9 -8
- angr/analyses/decompiler/ail_simplifier.py +115 -72
- angr/analyses/decompiler/callsite_maker.py +24 -11
- angr/analyses/decompiler/clinic.py +78 -43
- angr/analyses/decompiler/decompiler.py +18 -7
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +3 -1
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +21 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +84 -15
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +92 -11
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +53 -9
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +44 -7
- angr/analyses/decompiler/region_identifier.py +6 -4
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +287 -122
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +31 -13
- angr/analyses/decompiler/ssailification/rewriting.py +23 -15
- angr/analyses/decompiler/ssailification/rewriting_engine.py +105 -24
- angr/analyses/decompiler/ssailification/ssailification.py +22 -14
- angr/analyses/decompiler/structured_codegen/c.py +73 -137
- angr/analyses/decompiler/structuring/dream.py +22 -18
- angr/analyses/decompiler/structuring/phoenix.py +158 -41
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +37 -10
- angr/analyses/decompiler/structuring/structurer_nodes.py +4 -1
- angr/analyses/decompiler/utils.py +106 -21
- angr/analyses/deobfuscator/api_obf_finder.py +8 -5
- angr/analyses/deobfuscator/api_obf_type2_finder.py +18 -10
- 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 +6 -41
- angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +43 -25
- 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 +7 -5
- angr/analyses/variable_recovery/engine_vex.py +20 -4
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +30 -11
- angr/distributed/__init__.py +1 -1
- angr/engines/__init__.py +7 -8
- angr/engines/engine.py +1 -120
- angr/engines/failure.py +2 -2
- angr/engines/hook.py +2 -2
- angr/engines/light/engine.py +2 -2
- angr/engines/pcode/engine.py +2 -14
- 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 +124 -11
- angr/engines/syscall.py +2 -2
- angr/engines/unicorn.py +3 -3
- angr/engines/vex/heavy/heavy.py +3 -15
- angr/factory.py +12 -22
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/knowledge_plugins/variables/variable_manager.py +7 -5
- angr/sim_type.py +19 -17
- angr/simos/simos.py +3 -1
- 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/utils/types.py +48 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/METADATA +6 -6
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/RECORD +87 -86
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/LICENSE +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/WHEEL +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/entry_points.txt +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ from ailment.expression import (
|
|
|
27
27
|
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
28
28
|
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
29
29
|
from angr.utils.ail import is_phi_assignment, HasExprWalker
|
|
30
|
+
from angr.utils.ssa import has_call_in_between_stmts, has_store_stmt_in_between_stmts, has_load_expr_in_between_stmts
|
|
30
31
|
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
31
32
|
from angr.sim_variable import SimStackVariable, SimMemoryVariable, SimVariable
|
|
32
33
|
from angr.knowledge_plugins.propagations.states import Equivalence
|
|
@@ -98,6 +99,7 @@ class AILSimplifier(Analysis):
|
|
|
98
99
|
removed_vvar_ids: set[int] | None = None,
|
|
99
100
|
arg_vvars: dict[int, tuple[VirtualVariable, SimVariable]] | None = None,
|
|
100
101
|
avoid_vvar_ids: set[int] | None = None,
|
|
102
|
+
secondary_stackvars: set[int] | None = None,
|
|
101
103
|
):
|
|
102
104
|
self.func = func
|
|
103
105
|
self.func_graph = func_graph if func_graph is not None else func.graph
|
|
@@ -118,6 +120,7 @@ class AILSimplifier(Analysis):
|
|
|
118
120
|
self._arg_vvars = arg_vvars
|
|
119
121
|
self._avoid_vvar_ids = avoid_vvar_ids
|
|
120
122
|
self._propagator_dead_vvar_ids: set[int] = set()
|
|
123
|
+
self._secondary_stackvars: set[int] = secondary_stackvars if secondary_stackvars is not None else set()
|
|
121
124
|
|
|
122
125
|
self._calls_to_remove: set[CodeLocation] = set()
|
|
123
126
|
self._assignments_to_remove: set[CodeLocation] = set()
|
|
@@ -292,7 +295,7 @@ class AILSimplifier(Analysis):
|
|
|
292
295
|
|
|
293
296
|
narrowed = False
|
|
294
297
|
|
|
295
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
298
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
296
299
|
for block in self.func_graph.nodes():
|
|
297
300
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
298
301
|
|
|
@@ -424,6 +427,7 @@ class AILSimplifier(Analysis):
|
|
|
424
427
|
return ExprNarrowingInfo(False)
|
|
425
428
|
|
|
426
429
|
block = self.blocks.get(old_block, old_block)
|
|
430
|
+
assert loc.stmt_idx is not None
|
|
427
431
|
if loc.stmt_idx >= len(block.statements):
|
|
428
432
|
# missing a statement for whatever reason
|
|
429
433
|
return ExprNarrowingInfo(False)
|
|
@@ -551,14 +555,23 @@ class AILSimplifier(Analysis):
|
|
|
551
555
|
return None, None
|
|
552
556
|
return expr.size, ("expr", (expr,))
|
|
553
557
|
|
|
554
|
-
|
|
558
|
+
ops = walker.operations
|
|
559
|
+
first_op = ops[0]
|
|
560
|
+
if isinstance(first_op, BinaryOp) and first_op.op in {"Add", "Sub"}:
|
|
561
|
+
# expr + x
|
|
562
|
+
ops = ops[1:]
|
|
563
|
+
if not ops:
|
|
564
|
+
if expr is None:
|
|
565
|
+
return None, None
|
|
566
|
+
return expr.size, ("expr", (expr,))
|
|
567
|
+
first_op = ops[0]
|
|
555
568
|
if isinstance(first_op, Convert) and first_op.to_bits >= self.project.arch.byte_width:
|
|
556
569
|
# we need at least one byte!
|
|
557
570
|
return first_op.to_bits // self.project.arch.byte_width, ("convert", (first_op,))
|
|
558
571
|
if isinstance(first_op, BinaryOp):
|
|
559
572
|
second_op = None
|
|
560
|
-
if len(
|
|
561
|
-
second_op =
|
|
573
|
+
if len(ops) >= 2:
|
|
574
|
+
second_op = ops[1]
|
|
562
575
|
if (
|
|
563
576
|
first_op.op == "And"
|
|
564
577
|
and isinstance(first_op.operands[1], Const)
|
|
@@ -623,9 +636,9 @@ class AILSimplifier(Analysis):
|
|
|
623
636
|
block = blocks_by_addr_and_idx[(block_addr, block_idx)]
|
|
624
637
|
|
|
625
638
|
# only replace loads if there are stack arguments in this block
|
|
626
|
-
replace_loads = insn_addrs_using_stack_args is not None and
|
|
627
|
-
stmt.ins_addr for stmt in block.statements
|
|
628
|
-
|
|
639
|
+
replace_loads: bool = insn_addrs_using_stack_args is not None and bool(
|
|
640
|
+
{stmt.ins_addr for stmt in block.statements}.intersection(insn_addrs_using_stack_args)
|
|
641
|
+
)
|
|
629
642
|
|
|
630
643
|
# remove virtual variables in the avoid list
|
|
631
644
|
if self._avoid_vvar_ids:
|
|
@@ -662,7 +675,7 @@ class AILSimplifier(Analysis):
|
|
|
662
675
|
if not equivalence:
|
|
663
676
|
return simplified
|
|
664
677
|
|
|
665
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
678
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
666
679
|
for block in self.func_graph.nodes():
|
|
667
680
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
668
681
|
|
|
@@ -943,6 +956,8 @@ class AILSimplifier(Analysis):
|
|
|
943
956
|
for use_loc in all_use_locs:
|
|
944
957
|
if use_loc == eq.codeloc:
|
|
945
958
|
continue
|
|
959
|
+
assert use_loc.block_addr is not None
|
|
960
|
+
assert use_loc.stmt_idx is not None
|
|
946
961
|
block = addr_and_idx_to_block[(use_loc.block_addr, use_loc.block_idx)]
|
|
947
962
|
stmt = block.statements[use_loc.stmt_idx]
|
|
948
963
|
if isinstance(stmt, Assignment) or (isinstance(replace_with, Load) and isinstance(stmt, Store)):
|
|
@@ -954,11 +969,15 @@ class AILSimplifier(Analysis):
|
|
|
954
969
|
|
|
955
970
|
remove_initial_assignment = False # expression folding will take care of it
|
|
956
971
|
|
|
972
|
+
assert replace_with is not None
|
|
973
|
+
|
|
957
974
|
if any(not isinstance(use_and_expr[1], VirtualVariable) for _, use_and_expr in all_uses_with_def):
|
|
958
975
|
# if any of the uses are phi assignments, we skip
|
|
959
976
|
used_in_phi_assignment = False
|
|
960
977
|
for _, use_and_expr in all_uses_with_def:
|
|
961
978
|
u = use_and_expr[0]
|
|
979
|
+
assert u.block_addr is not None
|
|
980
|
+
assert u.stmt_idx is not None
|
|
962
981
|
block = addr_and_idx_to_block[(u.block_addr, u.block_idx)]
|
|
963
982
|
stmt = block.statements[u.stmt_idx]
|
|
964
983
|
if is_phi_assignment(stmt):
|
|
@@ -1120,8 +1139,6 @@ class AILSimplifier(Analysis):
|
|
|
1120
1139
|
than once after simplification and graph structuring where conditions might be duplicated (e.g., in Dream).
|
|
1121
1140
|
In such cases, the one-use expression folder in RegionSimplifier will perform this transformation.
|
|
1122
1141
|
"""
|
|
1123
|
-
# Disabled until https://github.com/angr/angr/issues/5112 and related folding issues are fixed
|
|
1124
|
-
return False
|
|
1125
1142
|
|
|
1126
1143
|
# pylint:disable=unreachable
|
|
1127
1144
|
simplified = False
|
|
@@ -1130,7 +1147,7 @@ class AILSimplifier(Analysis):
|
|
|
1130
1147
|
if not equivalence:
|
|
1131
1148
|
return simplified
|
|
1132
1149
|
|
|
1133
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
1150
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
1134
1151
|
for block in self.func_graph.nodes():
|
|
1135
1152
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
1136
1153
|
|
|
@@ -1168,6 +1185,8 @@ class AILSimplifier(Analysis):
|
|
|
1168
1185
|
),
|
|
1169
1186
|
eq.codeloc,
|
|
1170
1187
|
)
|
|
1188
|
+
assert the_def.codeloc.block_addr is not None
|
|
1189
|
+
assert the_def.codeloc.stmt_idx is not None
|
|
1171
1190
|
|
|
1172
1191
|
all_uses: set[tuple[CodeLocation, Any]] = set(rd.get_vvar_uses_with_expr(the_def.atom))
|
|
1173
1192
|
|
|
@@ -1176,6 +1195,8 @@ class AILSimplifier(Analysis):
|
|
|
1176
1195
|
u, used_expr = next(iter(all_uses))
|
|
1177
1196
|
if used_expr is None:
|
|
1178
1197
|
continue
|
|
1198
|
+
assert u.block_addr is not None
|
|
1199
|
+
assert u.stmt_idx is not None
|
|
1179
1200
|
|
|
1180
1201
|
if u in def_locations_to_remove:
|
|
1181
1202
|
# this use site has been altered by previous folding attempts. the corresponding statement will be
|
|
@@ -1196,41 +1217,28 @@ class AILSimplifier(Analysis):
|
|
|
1196
1217
|
if u.block_addr not in {b.addr for b in super_node_blocks}:
|
|
1197
1218
|
continue
|
|
1198
1219
|
|
|
1199
|
-
#
|
|
1200
|
-
#
|
|
1201
|
-
|
|
1202
|
-
#
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
# if usesite_expr_uses != defsite_expr_uses:
|
|
1222
|
-
# # special case: ok if this atom is assigned to at the def site and has not been overwritten
|
|
1223
|
-
# if len(usesite_expr_uses) == 1:
|
|
1224
|
-
# usesite_expr_use = next(iter(usesite_expr_uses))
|
|
1225
|
-
# if usesite_expr_use.atom == defsite_expr_atom and (
|
|
1226
|
-
# usesite_expr_use.codeloc == the_def.codeloc
|
|
1227
|
-
# or usesite_expr_use.codeloc.block_addr == call_addr
|
|
1228
|
-
# ):
|
|
1229
|
-
# continue
|
|
1230
|
-
# usesite_expr_def_outdated = True
|
|
1231
|
-
# break
|
|
1232
|
-
# if usesite_expr_def_outdated:
|
|
1233
|
-
# continue
|
|
1220
|
+
# ensure there are no other calls between the def site and the use site.
|
|
1221
|
+
# this is because we do not want to alter the order of calls.
|
|
1222
|
+
u_inclusive = CodeLocation(u.block_addr, u.stmt_idx + 1, block_idx=u.block_idx)
|
|
1223
|
+
# note that the target statement being a store is fine
|
|
1224
|
+
if (
|
|
1225
|
+
has_call_in_between_stmts(
|
|
1226
|
+
self.func_graph,
|
|
1227
|
+
addr_and_idx_to_block,
|
|
1228
|
+
the_def.codeloc,
|
|
1229
|
+
u_inclusive,
|
|
1230
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1231
|
+
)
|
|
1232
|
+
or has_store_stmt_in_between_stmts(self.func_graph, addr_and_idx_to_block, the_def.codeloc, u)
|
|
1233
|
+
or has_load_expr_in_between_stmts(
|
|
1234
|
+
self.func_graph,
|
|
1235
|
+
addr_and_idx_to_block,
|
|
1236
|
+
the_def.codeloc,
|
|
1237
|
+
u_inclusive,
|
|
1238
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1239
|
+
)
|
|
1240
|
+
):
|
|
1241
|
+
continue
|
|
1234
1242
|
|
|
1235
1243
|
# check if there are any calls in between the def site and the use site
|
|
1236
1244
|
if self._count_calls_in_supernodeblocks(super_node_blocks, the_def.codeloc, u) > 0:
|
|
@@ -1316,8 +1324,8 @@ class AILSimplifier(Analysis):
|
|
|
1316
1324
|
# keeping tracking of statements to remove and statements (as well as dead vvars) to keep allows us to handle
|
|
1317
1325
|
# cases where a statement defines more than one atoms, e.g., a call statement that defines both the return
|
|
1318
1326
|
# value and the floating-point return value.
|
|
1319
|
-
stmts_to_remove_per_block: dict[tuple[int, int], set[int]] = defaultdict(set)
|
|
1320
|
-
stmts_to_keep_per_block: dict[tuple[int, int], set[int]] = defaultdict(set)
|
|
1327
|
+
stmts_to_remove_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1328
|
+
stmts_to_keep_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1321
1329
|
dead_vvar_ids: set[int] = set()
|
|
1322
1330
|
|
|
1323
1331
|
# Find all statements that should be removed
|
|
@@ -1342,8 +1350,12 @@ class AILSimplifier(Analysis):
|
|
|
1342
1350
|
if rd.is_phi_vvar_id(def_.atom.varid):
|
|
1343
1351
|
# we always remove unused phi variables
|
|
1344
1352
|
pass
|
|
1353
|
+
elif def_.atom.varid in self._secondary_stackvars:
|
|
1354
|
+
# secondary stack variables are potentially removable
|
|
1355
|
+
pass
|
|
1345
1356
|
elif stackarg_offsets is not None:
|
|
1346
1357
|
# we always remove definitions for stack arguments
|
|
1358
|
+
assert def_.atom.stack_offset is not None
|
|
1347
1359
|
if (def_.atom.stack_offset & mask) not in stackarg_offsets:
|
|
1348
1360
|
continue
|
|
1349
1361
|
else:
|
|
@@ -1364,11 +1376,18 @@ class AILSimplifier(Analysis):
|
|
|
1364
1376
|
dead_vvar_ids.add(def_.atom.varid)
|
|
1365
1377
|
|
|
1366
1378
|
if not isinstance(def_.codeloc, ExternalCodeLocation):
|
|
1379
|
+
assert def_.codeloc.block_addr is not None
|
|
1380
|
+
assert def_.codeloc.stmt_idx is not None
|
|
1367
1381
|
stmts_to_remove_per_block[(def_.codeloc.block_addr, def_.codeloc.block_idx)].add(
|
|
1368
1382
|
def_.codeloc.stmt_idx
|
|
1369
1383
|
)
|
|
1370
1384
|
else:
|
|
1371
|
-
|
|
1385
|
+
if not isinstance(def_.codeloc, ExternalCodeLocation):
|
|
1386
|
+
assert def_.codeloc.block_addr is not None
|
|
1387
|
+
assert def_.codeloc.stmt_idx is not None
|
|
1388
|
+
stmts_to_keep_per_block[(def_.codeloc.block_addr, def_.codeloc.block_idx)].add(
|
|
1389
|
+
def_.codeloc.stmt_idx
|
|
1390
|
+
)
|
|
1372
1391
|
|
|
1373
1392
|
# find all phi variables that rely on variables that no longer exist
|
|
1374
1393
|
all_removed_var_ids = self._removed_vvar_ids.copy()
|
|
@@ -1380,6 +1399,7 @@ class AILSimplifier(Analysis):
|
|
|
1380
1399
|
vvarid in removed_vvar_ids for vvarid in phi_use_varids
|
|
1381
1400
|
):
|
|
1382
1401
|
loc = rd.all_vvar_definitions[rd.varid_to_vvar[phi_varid]]
|
|
1402
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1383
1403
|
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1384
1404
|
new_removed_vvar_ids.add(phi_varid)
|
|
1385
1405
|
all_removed_var_ids.add(phi_varid)
|
|
@@ -1391,11 +1411,13 @@ class AILSimplifier(Analysis):
|
|
|
1391
1411
|
redundant_phi_and_dirty_varids = self._find_cyclic_dependent_phis_and_dirty_vvars(rd)
|
|
1392
1412
|
for varid in redundant_phi_and_dirty_varids:
|
|
1393
1413
|
loc = rd.all_vvar_definitions[rd.varid_to_vvar[varid]]
|
|
1414
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1394
1415
|
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1395
1416
|
stmts_to_keep_per_block[(loc.block_addr, loc.block_idx)].discard(loc.stmt_idx)
|
|
1396
1417
|
|
|
1397
1418
|
for codeloc in self._calls_to_remove | self._assignments_to_remove:
|
|
1398
1419
|
# this call can be removed. make sure it exists in stmts_to_remove_per_block
|
|
1420
|
+
assert codeloc.block_addr is not None and codeloc.stmt_idx is not None
|
|
1399
1421
|
stmts_to_remove_per_block[codeloc.block_addr, codeloc.block_idx].add(codeloc.stmt_idx)
|
|
1400
1422
|
|
|
1401
1423
|
simplified = False
|
|
@@ -1488,8 +1510,36 @@ class AILSimplifier(Analysis):
|
|
|
1488
1510
|
|
|
1489
1511
|
return simplified
|
|
1490
1512
|
|
|
1513
|
+
@staticmethod
|
|
1514
|
+
def _get_vvar_used_by(
|
|
1515
|
+
vvar_id: int, rd: SRDAModel, blocks_dict: dict[tuple[int, int | None], Block]
|
|
1516
|
+
) -> set[int | None]:
|
|
1517
|
+
"""
|
|
1518
|
+
Get all atoms that use a specified virtual variable. The atoms are in the form of virtual variable ID or None
|
|
1519
|
+
(indicating the virtual variable is used by another statement like Store).
|
|
1520
|
+
|
|
1521
|
+
:param vvar_id: ID of the virtual variable.
|
|
1522
|
+
:param rd: The SRDA model.
|
|
1523
|
+
:return: The set of vvar use atoms.
|
|
1524
|
+
"""
|
|
1525
|
+
|
|
1526
|
+
vvar = rd.varid_to_vvar[vvar_id]
|
|
1527
|
+
used_by: set[int | None] = set()
|
|
1528
|
+
for used_vvar, loc in rd.all_vvar_uses[vvar]:
|
|
1529
|
+
if used_vvar is None:
|
|
1530
|
+
# no explicit reference
|
|
1531
|
+
used_by.add(None)
|
|
1532
|
+
elif loc.block_addr is not None:
|
|
1533
|
+
assert loc.stmt_idx is not None
|
|
1534
|
+
stmt = blocks_dict[(loc.block_addr, loc.block_idx)].statements[loc.stmt_idx]
|
|
1535
|
+
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
1536
|
+
used_by.add(stmt.dst.varid)
|
|
1537
|
+
else:
|
|
1538
|
+
used_by.add(None)
|
|
1539
|
+
return used_by
|
|
1540
|
+
|
|
1491
1541
|
def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel) -> set[int]:
|
|
1492
|
-
blocks_dict = {(bb.addr, bb.idx): bb for bb in self.func_graph}
|
|
1542
|
+
blocks_dict: dict[tuple[int, int | None], Block] = {(bb.addr, bb.idx): bb for bb in self.func_graph}
|
|
1493
1543
|
|
|
1494
1544
|
# find dirty vvars and vexccall vvars
|
|
1495
1545
|
dirty_vvar_ids = set()
|
|
@@ -1505,25 +1555,14 @@ class AILSimplifier(Analysis):
|
|
|
1505
1555
|
|
|
1506
1556
|
phi_and_dirty_vvar_ids = rd.phi_vvar_ids | dirty_vvar_ids
|
|
1507
1557
|
|
|
1508
|
-
vvar_used_by: dict[int, set[int]] = defaultdict(set)
|
|
1558
|
+
vvar_used_by: dict[int, set[int | None]] = defaultdict(set)
|
|
1509
1559
|
for var_id in phi_and_dirty_vvar_ids:
|
|
1510
1560
|
if var_id in rd.phivarid_to_varids:
|
|
1511
1561
|
for used_by_varid in rd.phivarid_to_varids[var_id]:
|
|
1512
|
-
vvar_used_by
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
for used_vvar, loc in rd.all_vvar_uses[vvar]:
|
|
1517
|
-
if used_vvar is None:
|
|
1518
|
-
# no explicit reference
|
|
1519
|
-
used_by.add(None)
|
|
1520
|
-
else:
|
|
1521
|
-
stmt = blocks_dict[loc.block_addr, loc.block_idx].statements[loc.stmt_idx]
|
|
1522
|
-
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
1523
|
-
used_by.add(stmt.dst.varid)
|
|
1524
|
-
else:
|
|
1525
|
-
used_by.add(None)
|
|
1526
|
-
vvar_used_by[var_id] |= used_by
|
|
1562
|
+
if used_by_varid not in vvar_used_by:
|
|
1563
|
+
vvar_used_by[used_by_varid] |= self._get_vvar_used_by(used_by_varid, rd, blocks_dict)
|
|
1564
|
+
vvar_used_by[used_by_varid].add(var_id) # probably unnecessary
|
|
1565
|
+
vvar_used_by[var_id] |= self._get_vvar_used_by(var_id, rd, blocks_dict)
|
|
1527
1566
|
|
|
1528
1567
|
g = networkx.DiGraph()
|
|
1529
1568
|
dummy_vvar_id = -1
|
|
@@ -1542,8 +1581,12 @@ class AILSimplifier(Analysis):
|
|
|
1542
1581
|
|
|
1543
1582
|
bail = False
|
|
1544
1583
|
for varid in scc:
|
|
1545
|
-
#
|
|
1546
|
-
|
|
1584
|
+
# ensure this vvar is not used by anything else outside the scc (regardless of whether this vvar is a
|
|
1585
|
+
# phi variable or not)
|
|
1586
|
+
if varid in vvar_used_by and None in vvar_used_by[varid]:
|
|
1587
|
+
bail = True
|
|
1588
|
+
break
|
|
1589
|
+
if bail is False:
|
|
1547
1590
|
succs = list(g.successors(varid))
|
|
1548
1591
|
if any(succ_varid not in scc for succ_varid in succs):
|
|
1549
1592
|
bail = True
|
|
@@ -1565,7 +1608,7 @@ class AILSimplifier(Analysis):
|
|
|
1565
1608
|
if rewriter_cls is None:
|
|
1566
1609
|
return False
|
|
1567
1610
|
|
|
1568
|
-
walker =
|
|
1611
|
+
walker = AILBlockWalker()
|
|
1569
1612
|
|
|
1570
1613
|
class _any_update:
|
|
1571
1614
|
"""
|
|
@@ -1574,7 +1617,9 @@ class AILSimplifier(Analysis):
|
|
|
1574
1617
|
|
|
1575
1618
|
v = False
|
|
1576
1619
|
|
|
1577
|
-
def _handle_expr(
|
|
1620
|
+
def _handle_expr(
|
|
1621
|
+
expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
1622
|
+
) -> Expression | None:
|
|
1578
1623
|
if isinstance(expr, VEXCCallExpression):
|
|
1579
1624
|
rewriter = rewriter_cls(expr, self.project.arch)
|
|
1580
1625
|
if rewriter.result is not None:
|
|
@@ -1585,8 +1630,6 @@ class AILSimplifier(Analysis):
|
|
|
1585
1630
|
return AILBlockWalker._handle_expr(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
1586
1631
|
|
|
1587
1632
|
blocks_by_addr_and_idx = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
1588
|
-
|
|
1589
|
-
walker = AILBlockWalker()
|
|
1590
1633
|
walker._handle_expr = _handle_expr
|
|
1591
1634
|
|
|
1592
1635
|
updated = False
|
|
@@ -45,7 +45,7 @@ class CallSiteMaker(Analysis):
|
|
|
45
45
|
self._ail_manager = ail_manager
|
|
46
46
|
|
|
47
47
|
self.result_block = None
|
|
48
|
-
self.stack_arg_offsets: set[tuple[int, int]] | None = None #
|
|
48
|
+
self.stack_arg_offsets: set[tuple[int, int]] | None = None # call ins addr, stack_offset
|
|
49
49
|
self.removed_vvar_ids: set[int] = set()
|
|
50
50
|
|
|
51
51
|
self._analyze()
|
|
@@ -372,7 +372,9 @@ class CallSiteMaker(Analysis):
|
|
|
372
372
|
|
|
373
373
|
return None
|
|
374
374
|
|
|
375
|
-
def _resolve_stack_argument(
|
|
375
|
+
def _resolve_stack_argument(
|
|
376
|
+
self, call_stmt: Stmt.Call, arg_loc
|
|
377
|
+
) -> tuple[Any, Any]: # pylint:disable=unused-argument
|
|
376
378
|
assert self._stack_pointer_tracker is not None
|
|
377
379
|
|
|
378
380
|
size = arg_loc.size
|
|
@@ -399,15 +401,26 @@ class CallSiteMaker(Analysis):
|
|
|
399
401
|
# FIXME: vvar may be larger than that we ask; we may need to chop the correct value of vvar
|
|
400
402
|
value = view.get_vvar_value(vvar)
|
|
401
403
|
if value is not None and not isinstance(value, Expr.Phi):
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
404
|
+
v: Expr.Expression = value
|
|
405
|
+
else:
|
|
406
|
+
v: Expr.Expression = Expr.VirtualVariable(
|
|
407
|
+
self._atom_idx(),
|
|
408
|
+
vvar.varid,
|
|
409
|
+
vvar.bits,
|
|
410
|
+
vvar.category,
|
|
411
|
+
oident=vvar.oident,
|
|
412
|
+
ins_addr=call_stmt.ins_addr,
|
|
413
|
+
)
|
|
414
|
+
if v.size > size:
|
|
415
|
+
v = Expr.Convert(
|
|
416
|
+
self._atom_idx(),
|
|
417
|
+
v.bits,
|
|
418
|
+
size * self.project.arch.byte_width,
|
|
419
|
+
False,
|
|
420
|
+
v,
|
|
421
|
+
ins_addr=call_stmt.ins_addr,
|
|
422
|
+
)
|
|
423
|
+
return None, v
|
|
411
424
|
|
|
412
425
|
return None, Expr.Load(
|
|
413
426
|
self._atom_idx(),
|