angr 9.2.142__py3-none-manylinux2014_x86_64.whl → 9.2.144__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 +22 -10
- angr/analyses/calling_convention/fact_collector.py +72 -14
- angr/analyses/cfg/cfg_base.py +7 -2
- angr/analyses/cfg/cfg_emulated.py +13 -4
- angr/analyses/cfg/cfg_fast.py +21 -60
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +12 -1
- angr/analyses/cfg/indirect_jump_resolvers/constant_value_manager.py +107 -0
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +2 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +6 -102
- angr/analyses/cfg/indirect_jump_resolvers/syscall_resolver.py +92 -0
- angr/analyses/complete_calling_conventions.py +18 -5
- angr/analyses/decompiler/ail_simplifier.py +95 -65
- angr/analyses/decompiler/clinic.py +162 -68
- angr/analyses/decompiler/decompiler.py +4 -4
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +49 -14
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +8 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +5 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +5 -0
- angr/analyses/decompiler/peephole_optimizations/__init__.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +37 -0
- angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +15 -1
- angr/analyses/decompiler/sequence_walker.py +8 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +2 -0
- angr/analyses/decompiler/ssailification/ssailification.py +10 -2
- angr/analyses/decompiler/ssailification/traversal_engine.py +17 -2
- angr/analyses/decompiler/structured_codegen/c.py +25 -4
- angr/analyses/decompiler/utils.py +13 -0
- angr/analyses/disassembly.py +3 -3
- angr/analyses/fcp/fcp.py +1 -4
- angr/analyses/s_propagator.py +40 -29
- angr/analyses/s_reaching_definitions/s_rda_model.py +45 -36
- angr/analyses/s_reaching_definitions/s_rda_view.py +6 -3
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +41 -42
- angr/analyses/typehoon/dfa.py +13 -3
- angr/analyses/typehoon/typehoon.py +60 -18
- angr/analyses/typehoon/typevars.py +11 -7
- angr/analyses/variable_recovery/engine_ail.py +19 -23
- angr/analyses/variable_recovery/engine_base.py +26 -30
- angr/analyses/variable_recovery/variable_recovery_fast.py +17 -21
- angr/calling_conventions.py +18 -8
- angr/knowledge_plugins/functions/function.py +29 -15
- angr/knowledge_plugins/key_definitions/constants.py +2 -2
- angr/knowledge_plugins/key_definitions/liveness.py +4 -4
- angr/lib/angr_native.so +0 -0
- angr/procedures/definitions/linux_kernel.py +5 -0
- angr/state_plugins/unicorn_engine.py +24 -8
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +1 -2
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +2 -2
- angr/utils/doms.py +40 -33
- angr/utils/graph.py +26 -20
- angr/utils/ssa/__init__.py +21 -14
- angr/utils/ssa/vvar_uses_collector.py +2 -2
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/METADATA +11 -8
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/RECORD +61 -58
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/WHEEL +1 -1
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/LICENSE +0 -0
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/entry_points.txt +0 -0
- {angr-9.2.142.dist-info → angr-9.2.144.dist-info}/top_level.txt +0 -0
|
@@ -36,6 +36,7 @@ from angr.knowledge_plugins.key_definitions.definition import Definition
|
|
|
36
36
|
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
37
37
|
from angr.errors import AngrRuntimeError
|
|
38
38
|
from angr.analyses import Analysis, AnalysesHub
|
|
39
|
+
from angr.utils.timing import timethis
|
|
39
40
|
from .ailgraph_walker import AILGraphWalker
|
|
40
41
|
from .expression_narrower import ExprNarrowingInfo, NarrowingInfoExtractor, ExpressionNarrower
|
|
41
42
|
from .block_simplifier import BlockSimplifier
|
|
@@ -202,6 +203,7 @@ class AILSimplifier(Analysis):
|
|
|
202
203
|
AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
|
|
203
204
|
self.blocks = {}
|
|
204
205
|
|
|
206
|
+
@timethis
|
|
205
207
|
def _compute_reaching_definitions(self) -> SRDAModel:
|
|
206
208
|
# Computing reaching definitions or return the cached one
|
|
207
209
|
if self._reaching_definitions is not None:
|
|
@@ -217,6 +219,7 @@ class AILSimplifier(Analysis):
|
|
|
217
219
|
self._reaching_definitions = rd
|
|
218
220
|
return rd
|
|
219
221
|
|
|
222
|
+
@timethis
|
|
220
223
|
def _compute_propagation(self) -> SPropagatorAnalysis:
|
|
221
224
|
# Propagate expressions or return the existing result
|
|
222
225
|
if self._propagator is not None:
|
|
@@ -233,6 +236,7 @@ class AILSimplifier(Analysis):
|
|
|
233
236
|
self._propagator_dead_vvar_ids = prop.dead_vvar_ids
|
|
234
237
|
return prop
|
|
235
238
|
|
|
239
|
+
@timethis
|
|
236
240
|
def _compute_equivalence(self) -> set[Equivalence]:
|
|
237
241
|
equivalence = set()
|
|
238
242
|
for block in self.func_graph:
|
|
@@ -281,6 +285,7 @@ class AILSimplifier(Analysis):
|
|
|
281
285
|
# Expression narrowing
|
|
282
286
|
#
|
|
283
287
|
|
|
288
|
+
@timethis
|
|
284
289
|
def _narrow_exprs(self) -> bool:
|
|
285
290
|
"""
|
|
286
291
|
A register may be used with full width even when only the lower bytes are really needed. This results in the
|
|
@@ -511,9 +516,9 @@ class AILSimplifier(Analysis):
|
|
|
511
516
|
atom = atom_queue.pop(0)
|
|
512
517
|
seen.add(atom)
|
|
513
518
|
|
|
514
|
-
|
|
519
|
+
expr_and_uses = rd.all_vvar_uses[atom.varid]
|
|
515
520
|
|
|
516
|
-
for
|
|
521
|
+
for expr, loc in set(expr_and_uses):
|
|
517
522
|
old_block = block_dict.get((loc.block_addr, loc.block_idx), None)
|
|
518
523
|
if old_block is None:
|
|
519
524
|
# missing a block for whatever reason
|
|
@@ -532,6 +537,7 @@ class AILSimplifier(Analysis):
|
|
|
532
537
|
)
|
|
533
538
|
if new_atom not in seen:
|
|
534
539
|
atom_queue.append(new_atom)
|
|
540
|
+
seen.add(new_atom)
|
|
535
541
|
else:
|
|
536
542
|
result.append((atom, loc, expr))
|
|
537
543
|
return result, phi_vars
|
|
@@ -659,6 +665,7 @@ class AILSimplifier(Analysis):
|
|
|
659
665
|
# Unifying local variables
|
|
660
666
|
#
|
|
661
667
|
|
|
668
|
+
@timethis
|
|
662
669
|
def _unify_local_variables(self) -> bool:
|
|
663
670
|
"""
|
|
664
671
|
Find variables that are definitely equivalent and then eliminate unnecessary copies.
|
|
@@ -822,14 +829,14 @@ class AILSimplifier(Analysis):
|
|
|
822
829
|
continue
|
|
823
830
|
|
|
824
831
|
# find all its uses
|
|
825
|
-
all_arg_copy_var_uses: set[tuple[
|
|
826
|
-
|
|
832
|
+
all_arg_copy_var_uses: set[tuple[Any, CodeLocation]] = rd.get_vvar_uses_with_expr(
|
|
833
|
+
arg_copy_def.atom
|
|
827
834
|
)
|
|
828
835
|
all_uses_with_def = set()
|
|
829
836
|
|
|
830
837
|
should_abort = False
|
|
831
838
|
for use in all_arg_copy_var_uses:
|
|
832
|
-
used_expr = use[
|
|
839
|
+
used_expr = use[0]
|
|
833
840
|
if used_expr is not None and used_expr.size != arg_copy_def.size:
|
|
834
841
|
should_abort = True
|
|
835
842
|
break
|
|
@@ -924,15 +931,19 @@ class AILSimplifier(Analysis):
|
|
|
924
931
|
|
|
925
932
|
# find all uses of this definition
|
|
926
933
|
# we make a copy of the set since we may touch the set (uses) when replacing expressions
|
|
927
|
-
all_uses: set[tuple[
|
|
934
|
+
all_uses: set[tuple[Any, CodeLocation]] = set(rd.all_vvar_uses[to_replace_def.atom.varid])
|
|
928
935
|
# make sure none of these uses are phi nodes (depends on more than one def)
|
|
929
936
|
all_uses_with_unique_def = set()
|
|
930
|
-
for
|
|
931
|
-
|
|
937
|
+
for expr_and_use in all_uses:
|
|
938
|
+
used_expr, use_loc = expr_and_use
|
|
932
939
|
defs_and_exprs = rd.get_uses_by_location(use_loc, exprs=True)
|
|
933
|
-
filtered_defs = {
|
|
940
|
+
filtered_defs = {
|
|
941
|
+
def_
|
|
942
|
+
for def_, expr_ in defs_and_exprs
|
|
943
|
+
if expr_ is not None and used_expr is not None and expr_.varid == used_expr.varid
|
|
944
|
+
}
|
|
934
945
|
if len(filtered_defs) == 1:
|
|
935
|
-
all_uses_with_unique_def.add(
|
|
946
|
+
all_uses_with_unique_def.add(expr_and_use)
|
|
936
947
|
else:
|
|
937
948
|
# optimization: break early
|
|
938
949
|
break
|
|
@@ -947,7 +958,7 @@ class AILSimplifier(Analysis):
|
|
|
947
958
|
|
|
948
959
|
if not (isinstance(replace_with, VirtualVariable) and replace_with.was_parameter):
|
|
949
960
|
assignment_ctr = 0
|
|
950
|
-
all_use_locs = {use_loc for
|
|
961
|
+
all_use_locs = {use_loc for _, use_loc in all_uses}
|
|
951
962
|
for use_loc in all_use_locs:
|
|
952
963
|
if use_loc == eq.codeloc:
|
|
953
964
|
continue
|
|
@@ -960,17 +971,17 @@ class AILSimplifier(Analysis):
|
|
|
960
971
|
if assignment_ctr > 1:
|
|
961
972
|
continue
|
|
962
973
|
|
|
963
|
-
all_uses_with_def = {(to_replace_def,
|
|
974
|
+
all_uses_with_def = {(to_replace_def, expr_and_use) for expr_and_use in all_uses}
|
|
964
975
|
|
|
965
976
|
remove_initial_assignment = False # expression folding will take care of it
|
|
966
977
|
|
|
967
978
|
assert replace_with is not None
|
|
968
979
|
|
|
969
|
-
if any(not isinstance(
|
|
980
|
+
if any(not isinstance(expr_and_use[0], VirtualVariable) for _, expr_and_use in all_uses_with_def):
|
|
970
981
|
# if any of the uses are phi assignments, we skip
|
|
971
982
|
used_in_phi_assignment = False
|
|
972
|
-
for _,
|
|
973
|
-
u =
|
|
983
|
+
for _, expr_and_use in all_uses_with_def:
|
|
984
|
+
u = expr_and_use[1]
|
|
974
985
|
assert u.block_addr is not None
|
|
975
986
|
assert u.stmt_idx is not None
|
|
976
987
|
block = addr_and_idx_to_block[(u.block_addr, u.block_idx)]
|
|
@@ -983,8 +994,8 @@ class AILSimplifier(Analysis):
|
|
|
983
994
|
|
|
984
995
|
# ensure the uses we consider are all after the eq location
|
|
985
996
|
filtered_all_uses_with_def = []
|
|
986
|
-
for def_,
|
|
987
|
-
u =
|
|
997
|
+
for def_, expr_and_use in all_uses_with_def:
|
|
998
|
+
u = expr_and_use[1]
|
|
988
999
|
if (
|
|
989
1000
|
u.block_addr == eq.codeloc.block_addr
|
|
990
1001
|
and u.block_idx == eq.codeloc.block_idx
|
|
@@ -992,7 +1003,7 @@ class AILSimplifier(Analysis):
|
|
|
992
1003
|
):
|
|
993
1004
|
# this use happens before the assignment - ignore it
|
|
994
1005
|
continue
|
|
995
|
-
filtered_all_uses_with_def.append((def_,
|
|
1006
|
+
filtered_all_uses_with_def.append((def_, expr_and_use))
|
|
996
1007
|
all_uses_with_def = filtered_all_uses_with_def
|
|
997
1008
|
|
|
998
1009
|
if not all_uses_with_def:
|
|
@@ -1004,8 +1015,8 @@ class AILSimplifier(Analysis):
|
|
|
1004
1015
|
|
|
1005
1016
|
# replace all uses
|
|
1006
1017
|
all_uses_replaced = True
|
|
1007
|
-
for def_,
|
|
1008
|
-
|
|
1018
|
+
for def_, expr_and_use in all_uses_with_def:
|
|
1019
|
+
used_expr, u = expr_and_use
|
|
1009
1020
|
|
|
1010
1021
|
use_expr_defns = []
|
|
1011
1022
|
for d in rd.get_uses_by_location(u):
|
|
@@ -1110,6 +1121,7 @@ class AILSimplifier(Analysis):
|
|
|
1110
1121
|
walker.walk_statement(stmt)
|
|
1111
1122
|
return len(walker.temps) > 0
|
|
1112
1123
|
|
|
1124
|
+
@timethis
|
|
1113
1125
|
def _fold_call_exprs(self) -> bool:
|
|
1114
1126
|
"""
|
|
1115
1127
|
Fold a call expression (statement) into other statements if the return value of the call expression (statement)
|
|
@@ -1183,11 +1195,11 @@ class AILSimplifier(Analysis):
|
|
|
1183
1195
|
assert the_def.codeloc.block_addr is not None
|
|
1184
1196
|
assert the_def.codeloc.stmt_idx is not None
|
|
1185
1197
|
|
|
1186
|
-
all_uses: set[tuple[
|
|
1198
|
+
all_uses: set[tuple[Any, CodeLocation]] = rd.get_vvar_uses_with_expr(the_def.atom)
|
|
1187
1199
|
|
|
1188
1200
|
if len(all_uses) != 1:
|
|
1189
1201
|
continue
|
|
1190
|
-
|
|
1202
|
+
used_expr, u = next(iter(all_uses))
|
|
1191
1203
|
if used_expr is None:
|
|
1192
1204
|
continue
|
|
1193
1205
|
assert u.block_addr is not None
|
|
@@ -1295,6 +1307,11 @@ class AILSimplifier(Analysis):
|
|
|
1295
1307
|
# check its predecessors
|
|
1296
1308
|
succ_predecessors = list(self.func_graph.predecessors(succ))
|
|
1297
1309
|
if len(succ_predecessors) == 1:
|
|
1310
|
+
if succ in lst:
|
|
1311
|
+
# we are about to form a loop - bad!
|
|
1312
|
+
# example: binary ce1897b492c80bf94083dd783aefb413ab1f6d8d4981adce8420f6669d0cb3e1, block
|
|
1313
|
+
# 0x2976EF7.
|
|
1314
|
+
break
|
|
1298
1315
|
lst.append(succ)
|
|
1299
1316
|
else:
|
|
1300
1317
|
break
|
|
@@ -1314,6 +1331,7 @@ class AILSimplifier(Analysis):
|
|
|
1314
1331
|
|
|
1315
1332
|
return False, None
|
|
1316
1333
|
|
|
1334
|
+
@timethis
|
|
1317
1335
|
def _iteratively_remove_dead_assignments(self) -> bool:
|
|
1318
1336
|
anything_removed = False
|
|
1319
1337
|
while True:
|
|
@@ -1323,6 +1341,7 @@ class AILSimplifier(Analysis):
|
|
|
1323
1341
|
self._rebuild_func_graph()
|
|
1324
1342
|
self._clear_cache()
|
|
1325
1343
|
|
|
1344
|
+
@timethis
|
|
1326
1345
|
def _remove_dead_assignments(self) -> bool:
|
|
1327
1346
|
|
|
1328
1347
|
# keeping tracking of statements to remove and statements (as well as dead vvars) to keep allows us to handle
|
|
@@ -1330,7 +1349,7 @@ class AILSimplifier(Analysis):
|
|
|
1330
1349
|
# value and the floating-point return value.
|
|
1331
1350
|
stmts_to_remove_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1332
1351
|
stmts_to_keep_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1333
|
-
dead_vvar_ids: set[int] =
|
|
1352
|
+
dead_vvar_ids: set[int] = self._removed_vvar_ids.copy()
|
|
1334
1353
|
dead_vvar_codelocs: set[CodeLocation] = set()
|
|
1335
1354
|
blocks: dict[tuple[int, int | None], Block] = {
|
|
1336
1355
|
(node.addr, node.idx): self.blocks.get(node, node) for node in self.func_graph.nodes()
|
|
@@ -1343,36 +1362,43 @@ class AILSimplifier(Analysis):
|
|
|
1343
1362
|
stackarg_offsets = (
|
|
1344
1363
|
{(tpl[1] & mask) for tpl in self._stack_arg_offsets} if self._stack_arg_offsets is not None else None
|
|
1345
1364
|
)
|
|
1365
|
+
|
|
1346
1366
|
while True:
|
|
1347
1367
|
new_dead_vars_found = False
|
|
1348
|
-
|
|
1349
|
-
|
|
1368
|
+
|
|
1369
|
+
# traverse all virtual variable definitions
|
|
1370
|
+
for vvar_id, codeloc in rd.all_vvar_definitions.items():
|
|
1371
|
+
if vvar_id in dead_vvar_ids:
|
|
1350
1372
|
continue
|
|
1351
|
-
|
|
1373
|
+
uses = None
|
|
1374
|
+
if vvar_id in self._propagator_dead_vvar_ids:
|
|
1352
1375
|
# we are definitely removing this variable if it has no uses
|
|
1353
|
-
uses = rd.all_vvar_uses[
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1376
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1377
|
+
|
|
1378
|
+
if uses is None:
|
|
1379
|
+
vvar = rd.varid_to_vvar[vvar_id]
|
|
1380
|
+
if vvar.was_stack:
|
|
1381
|
+
if not self._remove_dead_memdefs:
|
|
1382
|
+
if rd.is_phi_vvar_id(vvar_id):
|
|
1383
|
+
# we always remove unused phi variables
|
|
1384
|
+
pass
|
|
1385
|
+
elif vvar_id in self._secondary_stackvars:
|
|
1386
|
+
# secondary stack variables are potentially removable
|
|
1387
|
+
pass
|
|
1388
|
+
elif stackarg_offsets is not None:
|
|
1389
|
+
# we always remove definitions for stack arguments
|
|
1390
|
+
assert vvar.stack_offset is not None
|
|
1391
|
+
if (vvar.stack_offset & mask) not in stackarg_offsets:
|
|
1392
|
+
continue
|
|
1393
|
+
else:
|
|
1366
1394
|
continue
|
|
1367
|
-
|
|
1368
|
-
continue
|
|
1369
|
-
uses = rd.all_vvar_uses[vvar]
|
|
1395
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1370
1396
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1397
|
+
elif vvar.was_tmp or vvar.was_reg or vvar.was_parameter:
|
|
1398
|
+
uses = rd.all_vvar_uses[vvar_id]
|
|
1373
1399
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1400
|
+
else:
|
|
1401
|
+
uses = set()
|
|
1376
1402
|
|
|
1377
1403
|
# remove uses where vvars are going to be removed
|
|
1378
1404
|
filtered_uses_count = 0
|
|
@@ -1385,7 +1411,7 @@ class AILSimplifier(Analysis):
|
|
|
1385
1411
|
|
|
1386
1412
|
if filtered_uses_count == 0:
|
|
1387
1413
|
new_dead_vars_found = True
|
|
1388
|
-
dead_vvar_ids.add(
|
|
1414
|
+
dead_vvar_ids.add(vvar_id)
|
|
1389
1415
|
dead_vvar_codelocs.add(codeloc)
|
|
1390
1416
|
if not isinstance(codeloc, ExternalCodeLocation):
|
|
1391
1417
|
assert codeloc.block_addr is not None
|
|
@@ -1403,30 +1429,29 @@ class AILSimplifier(Analysis):
|
|
|
1403
1429
|
break
|
|
1404
1430
|
|
|
1405
1431
|
# find all phi variables that rely on variables that no longer exist
|
|
1406
|
-
all_removed_var_ids = self._removed_vvar_ids.copy()
|
|
1407
1432
|
removed_vvar_ids = self._removed_vvar_ids
|
|
1408
1433
|
while True:
|
|
1409
1434
|
new_removed_vvar_ids = set()
|
|
1410
1435
|
for phi_varid, phi_use_varids in rd.phivarid_to_varids.items():
|
|
1411
|
-
if phi_varid not in
|
|
1412
|
-
|
|
1413
|
-
):
|
|
1414
|
-
loc = rd.all_vvar_definitions[rd.varid_to_vvar[phi_varid]]
|
|
1436
|
+
if phi_varid not in dead_vvar_ids and any(vvarid in removed_vvar_ids for vvarid in phi_use_varids):
|
|
1437
|
+
loc = rd.all_vvar_definitions[phi_varid]
|
|
1415
1438
|
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1416
|
-
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]
|
|
1417
|
-
|
|
1418
|
-
|
|
1439
|
+
if loc.stmt_idx not in stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]:
|
|
1440
|
+
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1441
|
+
new_removed_vvar_ids.add(phi_varid)
|
|
1442
|
+
dead_vvar_ids.add(phi_varid)
|
|
1419
1443
|
if not new_removed_vvar_ids:
|
|
1420
1444
|
break
|
|
1421
1445
|
removed_vvar_ids = new_removed_vvar_ids
|
|
1422
1446
|
|
|
1423
1447
|
# find all phi variables that are only ever used by other phi variables
|
|
1424
|
-
redundant_phi_and_dirty_varids = self._find_cyclic_dependent_phis_and_dirty_vvars(rd)
|
|
1448
|
+
redundant_phi_and_dirty_varids = self._find_cyclic_dependent_phis_and_dirty_vvars(rd, dead_vvar_ids)
|
|
1425
1449
|
for varid in redundant_phi_and_dirty_varids:
|
|
1426
|
-
loc = rd.all_vvar_definitions[
|
|
1450
|
+
loc = rd.all_vvar_definitions[varid]
|
|
1427
1451
|
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1428
|
-
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]
|
|
1429
|
-
|
|
1452
|
+
if loc.stmt_idx not in stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)]:
|
|
1453
|
+
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1454
|
+
stmts_to_keep_per_block[(loc.block_addr, loc.block_idx)].discard(loc.stmt_idx)
|
|
1430
1455
|
|
|
1431
1456
|
for codeloc in self._calls_to_remove | self._assignments_to_remove:
|
|
1432
1457
|
# this call can be removed. make sure it exists in stmts_to_remove_per_block
|
|
@@ -1481,6 +1506,7 @@ class AILSimplifier(Analysis):
|
|
|
1481
1506
|
if self._statement_has_call_exprs(stmt):
|
|
1482
1507
|
if codeloc in self._calls_to_remove:
|
|
1483
1508
|
# it has a call and must be removed
|
|
1509
|
+
self._calls_to_remove.discard(codeloc)
|
|
1484
1510
|
simplified = True
|
|
1485
1511
|
continue
|
|
1486
1512
|
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
@@ -1538,9 +1564,8 @@ class AILSimplifier(Analysis):
|
|
|
1538
1564
|
:return: The set of vvar use atoms.
|
|
1539
1565
|
"""
|
|
1540
1566
|
|
|
1541
|
-
vvar = rd.varid_to_vvar[vvar_id]
|
|
1542
1567
|
used_by: set[int | None] = set()
|
|
1543
|
-
for used_vvar, loc in rd.all_vvar_uses[
|
|
1568
|
+
for used_vvar, loc in rd.all_vvar_uses[vvar_id]:
|
|
1544
1569
|
if used_vvar is None:
|
|
1545
1570
|
# no explicit reference
|
|
1546
1571
|
used_by.add(None)
|
|
@@ -1553,7 +1578,7 @@ class AILSimplifier(Analysis):
|
|
|
1553
1578
|
used_by.add(None)
|
|
1554
1579
|
return used_by
|
|
1555
1580
|
|
|
1556
|
-
def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel) -> set[int]:
|
|
1581
|
+
def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel, dead_vvar_ids: set[int]) -> set[int]:
|
|
1557
1582
|
blocks_dict: dict[tuple[int, int | None], Block] = {(bb.addr, bb.idx): bb for bb in self.func_graph}
|
|
1558
1583
|
|
|
1559
1584
|
# find dirty vvars and vexccall vvars
|
|
@@ -1568,16 +1593,21 @@ class AILSimplifier(Analysis):
|
|
|
1568
1593
|
):
|
|
1569
1594
|
dirty_vvar_ids.add(stmt.dst.varid)
|
|
1570
1595
|
|
|
1571
|
-
phi_and_dirty_vvar_ids = rd.phi_vvar_ids | dirty_vvar_ids
|
|
1596
|
+
phi_and_dirty_vvar_ids = (rd.phi_vvar_ids | dirty_vvar_ids).difference(dead_vvar_ids)
|
|
1572
1597
|
|
|
1573
1598
|
vvar_used_by: dict[int, set[int | None]] = defaultdict(set)
|
|
1574
1599
|
for var_id in phi_and_dirty_vvar_ids:
|
|
1575
1600
|
if var_id in rd.phivarid_to_varids:
|
|
1576
1601
|
for used_by_varid in rd.phivarid_to_varids[var_id]:
|
|
1602
|
+
if used_by_varid in dead_vvar_ids:
|
|
1603
|
+
# this variable no longer exists
|
|
1604
|
+
continue
|
|
1577
1605
|
if used_by_varid not in vvar_used_by:
|
|
1578
|
-
vvar_used_by[used_by_varid] |= self._get_vvar_used_by(
|
|
1606
|
+
vvar_used_by[used_by_varid] |= self._get_vvar_used_by(
|
|
1607
|
+
used_by_varid, rd, blocks_dict
|
|
1608
|
+
).difference(dead_vvar_ids)
|
|
1579
1609
|
vvar_used_by[used_by_varid].add(var_id) # probably unnecessary
|
|
1580
|
-
vvar_used_by[var_id] |= self._get_vvar_used_by(var_id, rd, blocks_dict)
|
|
1610
|
+
vvar_used_by[var_id] |= self._get_vvar_used_by(var_id, rd, blocks_dict).difference(dead_vvar_ids)
|
|
1581
1611
|
|
|
1582
1612
|
g = networkx.DiGraph()
|
|
1583
1613
|
dummy_vvar_id = -1
|