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
|
@@ -12,7 +12,13 @@ from .if_ import IfSimplifier
|
|
|
12
12
|
from .cascading_ifs import CascadingIfsRemover
|
|
13
13
|
from .ifelse import IfElseFlattener
|
|
14
14
|
from .loop import LoopSimplifier
|
|
15
|
-
from .expr_folding import
|
|
15
|
+
from .expr_folding import (
|
|
16
|
+
ExpressionCounter,
|
|
17
|
+
ExpressionFolder,
|
|
18
|
+
StoreStatementFinder,
|
|
19
|
+
ExpressionLocation,
|
|
20
|
+
InterferenceChecker,
|
|
21
|
+
)
|
|
16
22
|
from .cascading_cond_transformer import CascadingConditionTransformer
|
|
17
23
|
from .switch_expr_simplifier import SwitchExpressionSimplifier
|
|
18
24
|
from .switch_cluster_simplifier import SwitchClusterFinder, simplify_switch_clusters, simplify_lowered_switches
|
|
@@ -23,10 +29,17 @@ class RegionSimplifier(Analysis):
|
|
|
23
29
|
Simplifies a given region.
|
|
24
30
|
"""
|
|
25
31
|
|
|
26
|
-
def __init__(
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
func,
|
|
35
|
+
region,
|
|
36
|
+
arg_vvars: set[int] | None = None,
|
|
37
|
+
simplify_switches: bool = True,
|
|
38
|
+
simplify_ifelse: bool = True,
|
|
39
|
+
):
|
|
27
40
|
self.func = func
|
|
28
41
|
self.region = region
|
|
29
|
-
self.
|
|
42
|
+
self.arg_vvars = arg_vvars
|
|
30
43
|
self._simplify_switches = simplify_switches
|
|
31
44
|
self._should_simplify_ifelses = simplify_ifelse
|
|
32
45
|
|
|
@@ -54,7 +67,7 @@ class RegionSimplifier(Analysis):
|
|
|
54
67
|
# Remove empty nodes again
|
|
55
68
|
r = self._remove_empty_nodes(r)
|
|
56
69
|
|
|
57
|
-
if self.
|
|
70
|
+
if self.arg_vvars is not None:
|
|
58
71
|
# Fold expressions that are only used once into their use sites
|
|
59
72
|
r = self._fold_oneuse_expressions(r)
|
|
60
73
|
r = self._remove_empty_nodes(r)
|
|
@@ -88,8 +101,8 @@ class RegionSimplifier(Analysis):
|
|
|
88
101
|
#
|
|
89
102
|
|
|
90
103
|
def _fold_oneuse_expressions(self, region):
|
|
91
|
-
|
|
92
|
-
expr_counter = ExpressionCounter(region
|
|
104
|
+
# pylint:disable=unreachable
|
|
105
|
+
expr_counter = ExpressionCounter(region)
|
|
93
106
|
|
|
94
107
|
variable_assignments = {}
|
|
95
108
|
variable_uses = {}
|
|
@@ -126,7 +139,7 @@ class RegionSimplifier(Analysis):
|
|
|
126
139
|
# make sure all variables that var depends on has been assigned at most once
|
|
127
140
|
fail = False
|
|
128
141
|
for dep_var in deps:
|
|
129
|
-
if dep_var.
|
|
142
|
+
if self.arg_vvars is not None and dep_var in self.arg_vvars:
|
|
130
143
|
continue
|
|
131
144
|
if dep_var in expr_counter.assignments and len(expr_counter.assignments[dep_var]) > 1:
|
|
132
145
|
fail = True
|
|
@@ -151,8 +164,14 @@ class RegionSimplifier(Analysis):
|
|
|
151
164
|
del variable_assignments[var]
|
|
152
165
|
del variable_uses[var]
|
|
153
166
|
|
|
154
|
-
#
|
|
155
|
-
|
|
167
|
+
# ensure there is no interference between the call site and the use site
|
|
168
|
+
checker = InterferenceChecker(variable_assignments, variable_uses, region)
|
|
169
|
+
for varid in checker.interfered_assignments:
|
|
170
|
+
if varid in variable_assignments:
|
|
171
|
+
del variable_assignments[varid]
|
|
172
|
+
del variable_uses[varid]
|
|
173
|
+
# fold these expressions if possible
|
|
174
|
+
ExpressionFolder(variable_assignments, variable_uses, region)
|
|
156
175
|
return region
|
|
157
176
|
|
|
158
177
|
@staticmethod
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from ailment.manager import Manager
|
|
6
|
-
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement
|
|
6
|
+
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement, Jump
|
|
7
7
|
from ailment.expression import (
|
|
8
8
|
Expression,
|
|
9
9
|
Register,
|
|
@@ -19,6 +19,7 @@ from ailment.expression import (
|
|
|
19
19
|
ITE,
|
|
20
20
|
Tmp,
|
|
21
21
|
DirtyExpression,
|
|
22
|
+
Reinterpret,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
from angr.engines.light.engine import SimEngineNostmtAIL
|
|
@@ -183,6 +184,12 @@ class SimEngineSSARewriting(
|
|
|
183
184
|
|
|
184
185
|
return None
|
|
185
186
|
|
|
187
|
+
def _handle_stmt_Jump(self, stmt: Jump) -> Jump | None:
|
|
188
|
+
new_target = self._expr(stmt.target)
|
|
189
|
+
if new_target is not None:
|
|
190
|
+
return Jump(stmt.idx, new_target, stmt.target_idx, **stmt.tags)
|
|
191
|
+
return None
|
|
192
|
+
|
|
186
193
|
def _handle_stmt_ConditionalJump(self, stmt: ConditionalJump) -> ConditionalJump | None:
|
|
187
194
|
new_cond = self._expr(stmt.condition)
|
|
188
195
|
new_true_target = self._expr(stmt.true_target) if stmt.true_target is not None else None
|
|
@@ -429,7 +436,18 @@ class SimEngineSSARewriting(
|
|
|
429
436
|
def _handle_expr_Phi(self, expr):
|
|
430
437
|
return None
|
|
431
438
|
|
|
432
|
-
def _handle_expr_Reinterpret(self, expr):
|
|
439
|
+
def _handle_expr_Reinterpret(self, expr: Reinterpret) -> Reinterpret | None:
|
|
440
|
+
new_operand = self._expr(expr.operand)
|
|
441
|
+
if new_operand is not None:
|
|
442
|
+
return Reinterpret(
|
|
443
|
+
expr.idx,
|
|
444
|
+
expr.from_bits,
|
|
445
|
+
expr.from_type,
|
|
446
|
+
expr.to_bits,
|
|
447
|
+
expr.to_type,
|
|
448
|
+
new_operand,
|
|
449
|
+
**expr.tags,
|
|
450
|
+
)
|
|
433
451
|
return None
|
|
434
452
|
|
|
435
453
|
def _handle_expr_StackBaseOffset(self, expr):
|
|
@@ -205,7 +205,7 @@ class SimEngineSSATraversal(SimEngineLightAIL[TraversalState, None, None, None])
|
|
|
205
205
|
_handle_binop_Set = _handle_binop_Default
|
|
206
206
|
|
|
207
207
|
def _handle_unop_Default(self, expr):
|
|
208
|
-
self._expr(expr.
|
|
208
|
+
self._expr(expr.operand)
|
|
209
209
|
|
|
210
210
|
_handle_unop_BitwiseNeg = _handle_unop_Default
|
|
211
211
|
_handle_unop_Dereference = _handle_unop_Default
|
|
@@ -243,16 +243,17 @@ class SimEngineSSATraversal(SimEngineLightAIL[TraversalState, None, None, None])
|
|
|
243
243
|
if expr.maddr is not None:
|
|
244
244
|
self._expr(expr.maddr)
|
|
245
245
|
|
|
246
|
+
_handle_expr_Convert = _handle_unop_Default
|
|
247
|
+
_handle_expr_Reinterpret = _handle_unop_Default
|
|
248
|
+
|
|
246
249
|
def _handle_Dummy(self, expr):
|
|
247
250
|
pass
|
|
248
251
|
|
|
249
252
|
_handle_expr_VirtualVariable = _handle_Dummy
|
|
250
253
|
_handle_expr_Phi = _handle_Dummy
|
|
251
254
|
_handle_expr_Load = _handle_Dummy
|
|
252
|
-
_handle_expr_Convert = _handle_Dummy
|
|
253
255
|
_handle_expr_Const = _handle_Dummy
|
|
254
256
|
_handle_expr_MultiStatementExpression = _handle_Dummy
|
|
255
|
-
_handle_expr_Reinterpret = _handle_Dummy
|
|
256
257
|
_handle_expr_StackBaseOffset = _handle_Dummy
|
|
257
258
|
_handle_expr_BasePointerOffset = _handle_Dummy
|
|
258
259
|
_handle_expr_Call = _handle_Dummy
|
|
@@ -2504,6 +2504,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2504
2504
|
omit_func_header=False,
|
|
2505
2505
|
display_block_addrs=False,
|
|
2506
2506
|
display_vvar_ids=False,
|
|
2507
|
+
min_data_addr: int = 0x400_000,
|
|
2507
2508
|
):
|
|
2508
2509
|
super().__init__(flavor=flavor)
|
|
2509
2510
|
|
|
@@ -2578,6 +2579,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2578
2579
|
self.omit_func_header = omit_func_header
|
|
2579
2580
|
self.display_block_addrs = display_block_addrs
|
|
2580
2581
|
self.display_vvar_ids = display_vvar_ids
|
|
2582
|
+
self.min_data_addr = min_data_addr
|
|
2581
2583
|
self.text = None
|
|
2582
2584
|
self.map_pos_to_node = None
|
|
2583
2585
|
self.map_pos_to_addr = None
|
|
@@ -3519,8 +3521,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3519
3521
|
expr.value
|
|
3520
3522
|
]
|
|
3521
3523
|
inline_string = True
|
|
3522
|
-
elif isinstance(type_, SimTypePointer) and isinstance(type_.pts_to, SimTypeChar):
|
|
3523
|
-
# char*
|
|
3524
|
+
elif isinstance(type_, SimTypePointer) and isinstance(type_.pts_to, (SimTypeChar, SimTypeBottom)):
|
|
3525
|
+
# char* or void*
|
|
3524
3526
|
# Try to get a string
|
|
3525
3527
|
if (
|
|
3526
3528
|
self._cfg is not None
|
|
@@ -3583,11 +3585,16 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3583
3585
|
elif function_pointer:
|
|
3584
3586
|
self._function_pointers.add(expr.reference_variable)
|
|
3585
3587
|
|
|
3588
|
+
var_access = None
|
|
3586
3589
|
if variable is not None and not reference_values:
|
|
3587
3590
|
cvar = self._variable(variable, None)
|
|
3588
3591
|
offset = getattr(expr, "reference_variable_offset", 0)
|
|
3589
|
-
|
|
3592
|
+
var_access = self._access_constant_offset_reference(self._get_variable_reference(cvar), offset, None)
|
|
3590
3593
|
|
|
3594
|
+
if var_access is not None and expr.value >= self.min_data_addr:
|
|
3595
|
+
return var_access
|
|
3596
|
+
|
|
3597
|
+
reference_values["offset"] = var_access
|
|
3591
3598
|
return CConstant(expr.value, type_, reference_values=reference_values, tags=expr.tags, codegen=self)
|
|
3592
3599
|
|
|
3593
3600
|
def _handle_Expr_UnaryOp(self, expr, **kwargs):
|
|
@@ -10,7 +10,7 @@ import claripy
|
|
|
10
10
|
import ailment
|
|
11
11
|
|
|
12
12
|
from angr.utils.graph import GraphUtils
|
|
13
|
-
from angr.knowledge_plugins.cfg import
|
|
13
|
+
from angr.knowledge_plugins.cfg import IndirectJumpType
|
|
14
14
|
from angr.analyses.decompiler.graph_region import GraphRegion
|
|
15
15
|
from angr.analyses.decompiler.empty_node_remover import EmptyNodeRemover
|
|
16
16
|
from angr.analyses.decompiler.jumptable_entry_condition_rewriter import JumpTableEntryConditionRewriter
|
|
@@ -112,6 +112,7 @@ class DreamStructurer(StructurerBase):
|
|
|
112
112
|
|
|
113
113
|
loop_subgraph = self._region.graph
|
|
114
114
|
successors = self._region.successors
|
|
115
|
+
assert successors is not None
|
|
115
116
|
|
|
116
117
|
assert len(successors) <= 1
|
|
117
118
|
|
|
@@ -267,6 +268,7 @@ class DreamStructurer(StructurerBase):
|
|
|
267
268
|
|
|
268
269
|
def _to_loop_body_sequence(self, loop_head, loop_subgraph, loop_successors):
|
|
269
270
|
graph = self._region.graph_with_successors
|
|
271
|
+
assert graph is not None
|
|
270
272
|
loop_region_graph = networkx.DiGraph()
|
|
271
273
|
|
|
272
274
|
# TODO: Make sure the loop body has been structured
|
|
@@ -372,7 +374,7 @@ class DreamStructurer(StructurerBase):
|
|
|
372
374
|
node.condition_and_nodes = new_cond_and_nodes
|
|
373
375
|
|
|
374
376
|
if node.else_node is not None:
|
|
375
|
-
node.else_node = walker._handle(node.else_node)
|
|
377
|
+
node.else_node = walker._handle(node.else_node) # type: ignore
|
|
376
378
|
return node
|
|
377
379
|
|
|
378
380
|
def _handle_SwitchCaseNode(node, **kwargs): # pylint:disable=unused-argument
|
|
@@ -480,8 +482,6 @@ class DreamStructurer(StructurerBase):
|
|
|
480
482
|
:return: None
|
|
481
483
|
"""
|
|
482
484
|
|
|
483
|
-
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
484
|
-
|
|
485
485
|
addr2nodes: dict[int, set[CodeNode]] = defaultdict(set)
|
|
486
486
|
for node in seq.nodes:
|
|
487
487
|
addr2nodes[node.addr].add(node)
|
|
@@ -491,14 +491,14 @@ class DreamStructurer(StructurerBase):
|
|
|
491
491
|
node = seq.nodes[i]
|
|
492
492
|
|
|
493
493
|
# Jumptable_AddressLoadedFromMemory
|
|
494
|
-
r = self._make_switch_cases_address_loaded_from_memory(seq, i, node, addr2nodes
|
|
494
|
+
r = self._make_switch_cases_address_loaded_from_memory(seq, i, node, addr2nodes)
|
|
495
495
|
if r:
|
|
496
496
|
# we found a node that looks like a switch-case. seq.nodes are changed. resume to find the next such
|
|
497
497
|
# case
|
|
498
498
|
break
|
|
499
499
|
|
|
500
500
|
# Jumptable_AddressComputed
|
|
501
|
-
r = self._make_switch_cases_address_computed(seq, i, node, addr2nodes
|
|
501
|
+
r = self._make_switch_cases_address_computed(seq, i, node, addr2nodes)
|
|
502
502
|
if r:
|
|
503
503
|
break
|
|
504
504
|
|
|
@@ -506,9 +506,7 @@ class DreamStructurer(StructurerBase):
|
|
|
506
506
|
# we did not find any node that looks like a switch-case. exit.
|
|
507
507
|
break
|
|
508
508
|
|
|
509
|
-
def _make_switch_cases_address_loaded_from_memory(
|
|
510
|
-
self, seq, i, node, addr2nodes: dict[int, set[CodeNode]], jump_tables: dict[int, IndirectJump]
|
|
511
|
-
) -> bool:
|
|
509
|
+
def _make_switch_cases_address_loaded_from_memory(self, seq, i, node, addr2nodes: dict[int, set[CodeNode]]) -> bool:
|
|
512
510
|
"""
|
|
513
511
|
A typical jump table involves multiple nodes, which look like the following:
|
|
514
512
|
|
|
@@ -526,6 +524,8 @@ class DreamStructurer(StructurerBase):
|
|
|
526
524
|
|
|
527
525
|
try:
|
|
528
526
|
last_stmt = self.cond_proc.get_last_statement(node)
|
|
527
|
+
if not isinstance(last_stmt, ailment.Stmt.ConditionalJump):
|
|
528
|
+
return False
|
|
529
529
|
except EmptyBlockNotice:
|
|
530
530
|
return False
|
|
531
531
|
successor_addrs = extract_jump_targets(last_stmt)
|
|
@@ -533,14 +533,14 @@ class DreamStructurer(StructurerBase):
|
|
|
533
533
|
return False
|
|
534
534
|
|
|
535
535
|
for t in successor_addrs:
|
|
536
|
-
if t in addr2nodes and t in jump_tables:
|
|
536
|
+
if t in addr2nodes and t in self.jump_tables:
|
|
537
537
|
# this is a candidate!
|
|
538
538
|
target = t
|
|
539
539
|
break
|
|
540
540
|
else:
|
|
541
541
|
return False
|
|
542
542
|
|
|
543
|
-
jump_table = jump_tables[target]
|
|
543
|
+
jump_table = self.jump_tables[target]
|
|
544
544
|
if jump_table.type != IndirectJumpType.Jumptable_AddressLoadedFromMemory:
|
|
545
545
|
return False
|
|
546
546
|
|
|
@@ -563,13 +563,20 @@ class DreamStructurer(StructurerBase):
|
|
|
563
563
|
return False
|
|
564
564
|
|
|
565
565
|
# build switch-cases
|
|
566
|
+
assert jump_table.jumptable_entries is not None
|
|
566
567
|
cases, node_default, to_remove = self._switch_build_cases(
|
|
567
568
|
seq, cmp_lb, jump_table.jumptable_entries, i, node_b_addr, addr2nodes
|
|
568
569
|
)
|
|
569
570
|
# if we don't know what the end address of this switch-case structure is, let's figure it out
|
|
570
|
-
switch_end_addr =
|
|
571
|
-
|
|
571
|
+
switch_end_addr = (
|
|
572
|
+
node_b_addr
|
|
573
|
+
if node_default is None
|
|
574
|
+
else self._switch_find_switch_end_addr(cases, node_default, {nn.addr for nn in self._region.graph})
|
|
575
|
+
)
|
|
576
|
+
if switch_end_addr is not None:
|
|
577
|
+
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
572
578
|
|
|
579
|
+
assert last_stmt.ins_addr is not None
|
|
573
580
|
self._make_switch_cases_core(
|
|
574
581
|
seq,
|
|
575
582
|
i,
|
|
@@ -586,12 +593,10 @@ class DreamStructurer(StructurerBase):
|
|
|
586
593
|
|
|
587
594
|
return True
|
|
588
595
|
|
|
589
|
-
def _make_switch_cases_address_computed(
|
|
590
|
-
|
|
591
|
-
) -> bool:
|
|
592
|
-
if node.addr not in jump_tables:
|
|
596
|
+
def _make_switch_cases_address_computed(self, seq, i, node, addr2nodes: dict[int, set[CodeNode]]) -> bool:
|
|
597
|
+
if node.addr not in self.jump_tables:
|
|
593
598
|
return False
|
|
594
|
-
jump_table = jump_tables[node.addr]
|
|
599
|
+
jump_table = self.jump_tables[node.addr]
|
|
595
600
|
if jump_table.type != IndirectJumpType.Jumptable_AddressComputed:
|
|
596
601
|
return False
|
|
597
602
|
|
|
@@ -617,9 +622,11 @@ class DreamStructurer(StructurerBase):
|
|
|
617
622
|
cmp_expr, cmp_lb, cmp_ub = cmp # pylint:disable=unused-variable
|
|
618
623
|
|
|
619
624
|
jumptable_entries = jump_table.jumptable_entries
|
|
625
|
+
assert jumptable_entries is not None
|
|
620
626
|
|
|
621
627
|
if isinstance(last_stmt.false_target, ailment.Expr.Const):
|
|
622
628
|
default_addr = last_stmt.false_target.value
|
|
629
|
+
assert isinstance(default_addr, int)
|
|
623
630
|
else:
|
|
624
631
|
return False
|
|
625
632
|
|
|
@@ -656,8 +663,9 @@ class DreamStructurer(StructurerBase):
|
|
|
656
663
|
addr,
|
|
657
664
|
addr2nodes,
|
|
658
665
|
to_remove,
|
|
666
|
+
*,
|
|
667
|
+
jumptable_addr: int,
|
|
659
668
|
node_a=None,
|
|
660
|
-
jumptable_addr=None,
|
|
661
669
|
):
|
|
662
670
|
scnode = SwitchCaseNode(cmp_expr, cases, node_default, addr=addr)
|
|
663
671
|
scnode = CodeNode(scnode, node.reaching_condition)
|
|
@@ -715,6 +723,7 @@ class DreamStructurer(StructurerBase):
|
|
|
715
723
|
):
|
|
716
724
|
# unpacking is needed
|
|
717
725
|
for n in node_a.node.nodes:
|
|
726
|
+
assert n.addr is not None
|
|
718
727
|
if isinstance(n, ConditionNode):
|
|
719
728
|
unpacked = self._switch_unpack_condition_node(n, jumptable)
|
|
720
729
|
if unpacked is None:
|