angr 9.2.101__py3-none-win_amd64.whl → 9.2.103__py3-none-win_amd64.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/analysis.py +7 -6
- angr/analyses/calling_convention.py +33 -35
- angr/analyses/cdg.py +2 -4
- angr/analyses/cfg/cfb.py +4 -3
- angr/analyses/cfg/cfg_base.py +14 -14
- angr/analyses/cfg/cfg_emulated.py +3 -4
- angr/analyses/cfg/cfg_fast.py +46 -46
- angr/analyses/cfg/cfg_fast_soot.py +1 -2
- angr/analyses/cfg/cfg_job_base.py +2 -2
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +14 -13
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +5 -5
- angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +3 -3
- angr/analyses/complete_calling_conventions.py +13 -12
- angr/analyses/data_dep/data_dependency_analysis.py +24 -24
- angr/analyses/data_dep/dep_nodes.py +3 -3
- angr/analyses/ddg.py +1 -2
- angr/analyses/decompiler/ail_simplifier.py +35 -34
- angr/analyses/decompiler/block_io_finder.py +20 -20
- angr/analyses/decompiler/block_similarity.py +4 -6
- angr/analyses/decompiler/block_simplifier.py +17 -16
- angr/analyses/decompiler/callsite_maker.py +25 -10
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -3
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +2 -4
- angr/analyses/decompiler/clinic.py +250 -45
- angr/analyses/decompiler/condition_processor.py +15 -8
- angr/analyses/decompiler/decompilation_cache.py +7 -7
- angr/analyses/decompiler/decompilation_options.py +4 -4
- angr/analyses/decompiler/decompiler.py +19 -15
- angr/analyses/decompiler/expression_counters.py +10 -9
- angr/analyses/decompiler/goto_manager.py +2 -4
- angr/analyses/decompiler/graph_region.py +9 -9
- angr/analyses/decompiler/jump_target_collector.py +1 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +4 -3
- angr/analyses/decompiler/optimization_passes/code_motion.py +5 -6
- angr/analyses/decompiler/optimization_passes/const_derefs.py +4 -4
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +73 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +25 -3
- angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +6 -5
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +3 -0
- angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +2 -2
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +17 -17
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +12 -13
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +25 -21
- angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +3 -3
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +1 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +7 -7
- angr/analyses/decompiler/optimization_passes/spilled_register_finder.py +18 -0
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -3
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -2
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -3
- angr/analyses/decompiler/peephole_optimizations/base.py +13 -15
- angr/analyses/decompiler/peephole_optimizations/bswap.py +1 -3
- angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +72 -0
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -2
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +5 -10
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +3 -4
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +2 -3
- angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -2
- angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +4 -4
- angr/analyses/decompiler/redundant_label_remover.py +4 -5
- angr/analyses/decompiler/region_identifier.py +4 -5
- angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -2
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +19 -20
- angr/analyses/decompiler/region_simplifiers/goto.py +2 -3
- angr/analyses/decompiler/region_simplifiers/loop.py +1 -2
- angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -2
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +1 -3
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +19 -19
- angr/analyses/decompiler/return_maker.py +1 -2
- angr/analyses/decompiler/structured_codegen/base.py +5 -6
- angr/analyses/decompiler/structured_codegen/c.py +39 -38
- angr/analyses/decompiler/structuring/__init__.py +1 -1
- angr/analyses/decompiler/structuring/dream.py +17 -16
- angr/analyses/decompiler/structuring/phoenix.py +45 -46
- angr/analyses/decompiler/structuring/recursive_structurer.py +4 -4
- angr/analyses/decompiler/structuring/structurer_base.py +16 -15
- angr/analyses/decompiler/structuring/structurer_nodes.py +10 -9
- angr/analyses/decompiler/utils.py +17 -16
- angr/analyses/disassembly.py +7 -6
- angr/analyses/flirt.py +9 -9
- angr/analyses/forward_analysis/forward_analysis.py +15 -14
- angr/analyses/forward_analysis/visitors/function_graph.py +1 -2
- angr/analyses/forward_analysis/visitors/graph.py +16 -15
- angr/analyses/propagator/engine_ail.py +30 -26
- angr/analyses/propagator/outdated_definition_walker.py +8 -7
- angr/analyses/propagator/propagator.py +11 -13
- angr/analyses/proximity_graph.py +21 -21
- angr/analyses/reaching_definitions/__init__.py +3 -3
- angr/analyses/reaching_definitions/call_trace.py +3 -6
- angr/analyses/reaching_definitions/dep_graph.py +41 -48
- angr/analyses/reaching_definitions/engine_ail.py +11 -5
- angr/analyses/reaching_definitions/engine_vex.py +9 -8
- angr/analyses/reaching_definitions/function_handler.py +51 -34
- angr/analyses/reaching_definitions/heap_allocator.py +3 -4
- angr/analyses/reaching_definitions/rd_initializer.py +8 -8
- angr/analyses/reaching_definitions/rd_state.py +57 -58
- angr/analyses/reaching_definitions/reaching_definitions.py +18 -17
- angr/analyses/reaching_definitions/subject.py +2 -3
- angr/analyses/stack_pointer_tracker.py +15 -6
- angr/analyses/typehoon/dfa.py +4 -4
- angr/analyses/typehoon/simple_solver.py +48 -52
- angr/analyses/typehoon/translator.py +3 -6
- angr/analyses/typehoon/typeconsts.py +13 -14
- angr/analyses/typehoon/typehoon.py +9 -9
- angr/analyses/typehoon/typevars.py +18 -17
- angr/analyses/variable_recovery/engine_ail.py +5 -5
- angr/analyses/variable_recovery/engine_base.py +25 -21
- angr/analyses/variable_recovery/irsb_scanner.py +8 -9
- angr/analyses/variable_recovery/variable_recovery.py +1 -2
- angr/analyses/variable_recovery/variable_recovery_base.py +14 -13
- angr/analyses/variable_recovery/variable_recovery_fast.py +8 -8
- angr/analyses/veritesting.py +1 -2
- angr/analyses/vfg.py +57 -56
- angr/analyses/xrefs.py +1 -2
- angr/angrdb/db.py +7 -7
- angr/angrdb/serializers/kb.py +16 -13
- angr/angrdb/serializers/loader.py +1 -2
- angr/angrdb/serializers/structured_code.py +2 -2
- angr/annocfg.py +1 -2
- angr/block.py +16 -6
- angr/calling_conventions.py +27 -27
- angr/code_location.py +8 -8
- angr/codenode.py +1 -2
- angr/concretization_strategies/max.py +1 -3
- angr/distributed/server.py +1 -3
- angr/distributed/worker.py +1 -2
- angr/engines/engine.py +2 -3
- angr/engines/light/engine.py +4 -4
- angr/engines/pcode/behavior.py +20 -2
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/engine.py +7 -7
- angr/engines/pcode/lifter.py +78 -77
- angr/engines/vex/claripy/ccall.py +1 -2
- angr/engines/vex/claripy/datalayer.py +1 -2
- angr/engines/vex/light/light.py +1 -2
- angr/exploration_techniques/tracer.py +4 -4
- angr/factory.py +12 -15
- angr/flirt/__init__.py +8 -8
- angr/flirt/build_sig.py +2 -3
- angr/keyed_region.py +2 -2
- angr/knowledge_base/knowledge_base.py +3 -3
- angr/knowledge_plugins/callsite_prototypes.py +4 -6
- angr/knowledge_plugins/cfg/cfg_manager.py +19 -6
- angr/knowledge_plugins/cfg/cfg_model.py +26 -27
- angr/knowledge_plugins/cfg/cfg_node.py +2 -2
- angr/knowledge_plugins/cfg/indirect_jump.py +6 -8
- angr/knowledge_plugins/cfg/memory_data.py +8 -9
- angr/knowledge_plugins/custom_strings.py +1 -3
- angr/knowledge_plugins/debug_variables.py +2 -2
- angr/knowledge_plugins/functions/function.py +21 -22
- angr/knowledge_plugins/functions/function_manager.py +5 -5
- angr/knowledge_plugins/indirect_jumps.py +1 -3
- angr/knowledge_plugins/key_definitions/atoms.py +7 -7
- angr/knowledge_plugins/key_definitions/definition.py +14 -14
- angr/knowledge_plugins/key_definitions/environment.py +5 -7
- angr/knowledge_plugins/key_definitions/heap_address.py +1 -3
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +3 -2
- angr/knowledge_plugins/key_definitions/live_definitions.py +60 -59
- angr/knowledge_plugins/key_definitions/liveness.py +16 -16
- angr/knowledge_plugins/key_definitions/rd_model.py +15 -15
- angr/knowledge_plugins/key_definitions/uses.py +11 -11
- angr/knowledge_plugins/patches.py +4 -8
- angr/knowledge_plugins/propagations/prop_value.py +10 -9
- angr/knowledge_plugins/propagations/propagation_manager.py +3 -5
- angr/knowledge_plugins/propagations/propagation_model.py +9 -9
- angr/knowledge_plugins/propagations/states.py +52 -22
- angr/knowledge_plugins/structured_code/manager.py +2 -2
- angr/knowledge_plugins/sync/sync_controller.py +3 -3
- angr/knowledge_plugins/variables/variable_access.py +4 -4
- angr/knowledge_plugins/variables/variable_manager.py +56 -39
- angr/knowledge_plugins/xrefs/xref.py +9 -11
- angr/knowledge_plugins/xrefs/xref_manager.py +3 -4
- angr/lib/angr_native.dll +0 -0
- angr/misc/ansi.py +1 -2
- angr/misc/autoimport.py +3 -3
- angr/misc/plugins.py +9 -9
- angr/procedures/definitions/__init__.py +16 -16
- angr/procedures/definitions/linux_kernel.py +1 -1
- angr/procedures/definitions/parse_win32json.py +1 -1
- angr/procedures/java_jni/__init__.py +1 -1
- angr/procedures/java_jni/array_operations.py +1 -2
- angr/procedures/java_jni/method_calls.py +1 -2
- angr/procedures/posix/inet_ntoa.py +1 -2
- angr/procedures/stubs/format_parser.py +3 -3
- angr/project.py +13 -11
- angr/sim_manager.py +12 -12
- angr/sim_procedure.py +7 -3
- angr/sim_state.py +2 -2
- angr/sim_type.py +60 -45
- angr/sim_variable.py +5 -5
- angr/simos/simos.py +1 -2
- angr/simos/userland.py +1 -2
- angr/state_plugins/callstack.py +3 -2
- angr/state_plugins/history.py +1 -2
- angr/state_plugins/solver.py +34 -34
- angr/storage/memory_mixins/__init__.py +4 -3
- angr/storage/memory_mixins/actions_mixin.py +1 -3
- angr/storage/memory_mixins/address_concretization_mixin.py +1 -3
- angr/storage/memory_mixins/convenient_mappings_mixin.py +3 -4
- angr/storage/memory_mixins/default_filler_mixin.py +1 -1
- angr/storage/memory_mixins/label_merger_mixin.py +2 -2
- angr/storage/memory_mixins/multi_value_merger_mixin.py +4 -3
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +9 -8
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +12 -11
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +8 -8
- angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +2 -3
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +10 -11
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +11 -10
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +18 -17
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +12 -11
- angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +3 -3
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +3 -2
- angr/storage/memory_mixins/regioned_memory/region_data.py +1 -2
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +2 -2
- angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +3 -3
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +18 -21
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -2
- angr/storage/memory_mixins/symbolic_merger_mixin.py +3 -2
- angr/storage/memory_mixins/top_merger_mixin.py +3 -2
- angr/storage/memory_object.py +2 -4
- angr/utils/algo.py +3 -2
- angr/utils/dynamic_dictlist.py +5 -5
- angr/utils/formatting.py +4 -4
- angr/utils/funcid.py +1 -2
- angr/utils/graph.py +5 -6
- angr/utils/library.py +5 -5
- angr/utils/mp.py +5 -4
- angr/utils/segment_list.py +3 -4
- angr/utils/typing.py +3 -2
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/RECORD +240 -237
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
|
@@ -216,7 +216,7 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
216
216
|
|
|
217
217
|
@staticmethod
|
|
218
218
|
def _optimize_convert(expr: Convert):
|
|
219
|
-
if isinstance(expr.operand, Const):
|
|
219
|
+
if isinstance(expr.operand, Const) and expr.from_type == Convert.TYPE_INT and expr.to_type == Convert.TYPE_INT:
|
|
220
220
|
if expr.from_bits > expr.to_bits:
|
|
221
221
|
# truncation
|
|
222
222
|
mask = (1 << expr.to_bits) - 1
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=arguments-differ
|
|
2
|
-
from typing import Tuple, Optional, Dict, List
|
|
3
2
|
import string
|
|
4
3
|
|
|
5
4
|
from archinfo import Endness
|
|
@@ -25,7 +24,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
25
24
|
stmt_classes = (Store,)
|
|
26
25
|
|
|
27
26
|
def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
|
|
28
|
-
if isinstance(stmt.data, Const):
|
|
27
|
+
if isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
|
|
29
28
|
r, s = self.is_integer_likely_a_string(stmt.data.value, stmt.data.size, stmt.endness)
|
|
30
29
|
if r:
|
|
31
30
|
# replace it with a call to strncpy
|
|
@@ -43,9 +42,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
43
42
|
|
|
44
43
|
# scan forward in the current block to find all consecutive constant stores
|
|
45
44
|
if block is not None and stmt_idx is not None:
|
|
46
|
-
all_constant_stores:
|
|
47
|
-
block, stmt_idx
|
|
48
|
-
)
|
|
45
|
+
all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
|
|
49
46
|
if all_constant_stores:
|
|
50
47
|
offsets = sorted(all_constant_stores.keys())
|
|
51
48
|
next_offset = min(offsets)
|
|
@@ -87,7 +84,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
87
84
|
return None
|
|
88
85
|
|
|
89
86
|
@staticmethod
|
|
90
|
-
def stride_to_int(stride:
|
|
87
|
+
def stride_to_int(stride: list[tuple[int, int, Const]]) -> tuple[int, int]:
|
|
91
88
|
stride = sorted(stride, key=lambda x: x[0])
|
|
92
89
|
n = 0
|
|
93
90
|
size = 0
|
|
@@ -98,7 +95,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
98
95
|
return n, size
|
|
99
96
|
|
|
100
97
|
@staticmethod
|
|
101
|
-
def collect_constant_stores(block, starting_stmt_idx: int) ->
|
|
98
|
+
def collect_constant_stores(block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
|
|
102
99
|
r = {}
|
|
103
100
|
for idx, stmt in enumerate(block.statements):
|
|
104
101
|
if idx < starting_stmt_idx:
|
|
@@ -112,9 +109,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
112
109
|
return r
|
|
113
110
|
|
|
114
111
|
@staticmethod
|
|
115
|
-
def is_integer_likely_a_string(
|
|
116
|
-
v: int, size: int, endness: Endness, min_length: int = 4
|
|
117
|
-
) -> Tuple[bool, Optional[str]]:
|
|
112
|
+
def is_integer_likely_a_string(v: int, size: int, endness: Endness, min_length: int = 4) -> tuple[bool, str | None]:
|
|
118
113
|
# we need at least four bytes of printable characters
|
|
119
114
|
|
|
120
115
|
chars = []
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=arguments-differ
|
|
2
|
-
from typing import List, Tuple, Optional
|
|
3
2
|
|
|
4
3
|
from ailment.expression import Expression, BinaryOp, Const, Register, StackBaseOffset
|
|
5
4
|
from ailment.statement import Call, Store
|
|
@@ -18,7 +17,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
|
|
|
18
17
|
NAME = "Consolidate multiple inlined strcpy calls"
|
|
19
18
|
stmt_classes = ((Call, Call), (Call, Store))
|
|
20
19
|
|
|
21
|
-
def optimize(self, stmts:
|
|
20
|
+
def optimize(self, stmts: list[Call], **kwargs):
|
|
22
21
|
last_stmt, stmt = stmts
|
|
23
22
|
if InlinedStrcpyConsolidation._is_inlined_strcpy(last_stmt):
|
|
24
23
|
s_last: bytes = self.kb.custom_strings[last_stmt.args[1].value]
|
|
@@ -79,7 +78,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
|
|
|
79
78
|
return False
|
|
80
79
|
|
|
81
80
|
@staticmethod
|
|
82
|
-
def _parse_addr(addr: Expression) ->
|
|
81
|
+
def _parse_addr(addr: Expression) -> tuple[Expression, int]:
|
|
83
82
|
if isinstance(addr, Register):
|
|
84
83
|
return addr, 0
|
|
85
84
|
if isinstance(addr, StackBaseOffset):
|
|
@@ -95,7 +94,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
|
|
|
95
94
|
return addr, 0
|
|
96
95
|
|
|
97
96
|
@staticmethod
|
|
98
|
-
def _get_delta(addr_0: Expression, addr_1: Expression) ->
|
|
97
|
+
def _get_delta(addr_0: Expression, addr_1: Expression) -> int | None:
|
|
99
98
|
base_0, offset_0 = InlinedStrcpyConsolidation._parse_addr(addr_0)
|
|
100
99
|
base_1, offset_1 = InlinedStrcpyConsolidation._parse_addr(addr_1)
|
|
101
100
|
if base_0.likes(base_1):
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=arguments-differ
|
|
2
|
-
from typing import Tuple, Optional, Dict, List
|
|
3
2
|
import string
|
|
4
3
|
|
|
5
4
|
from archinfo import Endness
|
|
@@ -25,7 +24,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
|
25
24
|
stmt_classes = (Store,)
|
|
26
25
|
|
|
27
26
|
def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
|
|
28
|
-
if isinstance(stmt.data, Const):
|
|
27
|
+
if isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
|
|
29
28
|
r, s = self.is_integer_likely_a_wide_string(stmt.data.value, stmt.data.size, stmt.endness)
|
|
30
29
|
if r:
|
|
31
30
|
# replace it with a call to strncpy
|
|
@@ -43,9 +42,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
|
43
42
|
|
|
44
43
|
# scan forward in the current block to find all consecutive constant stores
|
|
45
44
|
if block is not None and stmt_idx is not None:
|
|
46
|
-
all_constant_stores:
|
|
47
|
-
block, stmt_idx
|
|
48
|
-
)
|
|
45
|
+
all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
|
|
49
46
|
if all_constant_stores:
|
|
50
47
|
offsets = sorted(all_constant_stores.keys())
|
|
51
48
|
next_offset = min(offsets)
|
|
@@ -87,7 +84,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
|
87
84
|
return None
|
|
88
85
|
|
|
89
86
|
@staticmethod
|
|
90
|
-
def stride_to_int(stride:
|
|
87
|
+
def stride_to_int(stride: list[tuple[int, int, Const]]) -> tuple[int, int]:
|
|
91
88
|
stride = sorted(stride, key=lambda x: x[0])
|
|
92
89
|
n = 0
|
|
93
90
|
size = 0
|
|
@@ -98,7 +95,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
|
98
95
|
return n, size
|
|
99
96
|
|
|
100
97
|
@staticmethod
|
|
101
|
-
def collect_constant_stores(block, starting_stmt_idx: int) ->
|
|
98
|
+
def collect_constant_stores(block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
|
|
102
99
|
r = {}
|
|
103
100
|
for idx, stmt in enumerate(block.statements):
|
|
104
101
|
if idx < starting_stmt_idx:
|
|
@@ -112,17 +109,17 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
|
112
109
|
return r
|
|
113
110
|
|
|
114
111
|
@staticmethod
|
|
115
|
-
def even_offsets_are_zero(lst:
|
|
112
|
+
def even_offsets_are_zero(lst: list[str]) -> bool:
|
|
116
113
|
return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 0)
|
|
117
114
|
|
|
118
115
|
@staticmethod
|
|
119
|
-
def odd_offsets_are_zero(lst:
|
|
116
|
+
def odd_offsets_are_zero(lst: list[str]) -> bool:
|
|
120
117
|
return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 1)
|
|
121
118
|
|
|
122
119
|
@staticmethod
|
|
123
120
|
def is_integer_likely_a_wide_string(
|
|
124
121
|
v: int, size: int, endness: Endness, min_length: int = 4
|
|
125
|
-
) ->
|
|
122
|
+
) -> tuple[bool, str | None]:
|
|
126
123
|
# we need at least four bytes of printable characters
|
|
127
124
|
|
|
128
125
|
chars = []
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=too-many-boolean-expressions
|
|
2
|
-
from typing import Optional, Dict, Tuple
|
|
3
2
|
from ailment.expression import Expression, BinaryOp, Const, Convert, ITE
|
|
4
3
|
|
|
5
4
|
from .base import PeepholeOptimizationExprBase
|
|
@@ -36,7 +35,7 @@ class RewriteBitExtractions(PeepholeOptimizationExprBase):
|
|
|
36
35
|
|
|
37
36
|
return None
|
|
38
37
|
|
|
39
|
-
def _extract_bitoffset_to_expr_mapping(self, expr: BinaryOp) ->
|
|
38
|
+
def _extract_bitoffset_to_expr_mapping(self, expr: BinaryOp) -> dict[int, Expression] | None:
|
|
40
39
|
d = {}
|
|
41
40
|
if isinstance(expr, BinaryOp) and expr.op == "Or":
|
|
42
41
|
for arg in expr.operands:
|
|
@@ -61,7 +60,7 @@ class RewriteBitExtractions(PeepholeOptimizationExprBase):
|
|
|
61
60
|
return d
|
|
62
61
|
|
|
63
62
|
@staticmethod
|
|
64
|
-
def _get_setbit(expr: Expression) ->
|
|
63
|
+
def _get_setbit(expr: Expression) -> tuple[int, Expression] | None:
|
|
65
64
|
"""
|
|
66
65
|
Test if expr is a single-bit expression, and if it is, return the bit offset that it sets and the inner
|
|
67
66
|
expression that sets the bit.
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from typing import Optional, Tuple
|
|
2
1
|
from ailment.expression import Convert, BinaryOp, Const, ITE, Expression, Register
|
|
3
2
|
|
|
4
3
|
from .base import PeepholeOptimizationExprBase
|
|
@@ -75,7 +74,7 @@ class SarToSignedDiv(PeepholeOptimizationExprBase):
|
|
|
75
74
|
return None
|
|
76
75
|
|
|
77
76
|
@staticmethod
|
|
78
|
-
def _check_signedness(expr) ->
|
|
77
|
+
def _check_signedness(expr) -> tuple[bool, int, Expression] | None:
|
|
79
78
|
# return a tuple of ( is_signed (False for is_unsigned), bits of the expression to test for signedness, and the
|
|
80
79
|
# expression itself ).
|
|
81
80
|
if isinstance(expr, BinaryOp):
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
3
|
from ailment.expression import UnaryOp, BinaryOp, StackBaseOffset, Const
|
|
4
4
|
|
|
@@ -30,8 +30,8 @@ class TidyStackAddr(PeepholeOptimizationExprBase):
|
|
|
30
30
|
return None
|
|
31
31
|
|
|
32
32
|
# consolidate all expressions into a list of expressions with their signs (True for +, False for -)
|
|
33
|
-
all_operands:
|
|
34
|
-
stack:
|
|
33
|
+
all_operands: list[tuple[bool, "Expression"]] = []
|
|
34
|
+
stack: list[tuple[bool, "Expression"]] = [(True, expr)]
|
|
35
35
|
stackbase_count = 0
|
|
36
36
|
while stack:
|
|
37
37
|
sign, item = stack.pop(0)
|
|
@@ -54,7 +54,7 @@ class TidyStackAddr(PeepholeOptimizationExprBase):
|
|
|
54
54
|
|
|
55
55
|
# collect all constants until the next StackBaseOffset object and merge them into the prior StackBaseOffset
|
|
56
56
|
# object.
|
|
57
|
-
stackbaseoffset_objs:
|
|
57
|
+
stackbaseoffset_objs: list[tuple[bool, StackBaseOffset]] = []
|
|
58
58
|
|
|
59
59
|
# find StackBaseOffset objects and record their indices
|
|
60
60
|
stackbaseoffset_indices = []
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=unused-argument
|
|
2
|
-
from typing import Set, Optional, Tuple, Dict
|
|
3
2
|
|
|
4
3
|
import ailment
|
|
5
4
|
|
|
@@ -18,12 +17,12 @@ class RedundantLabelRemover:
|
|
|
18
17
|
anywhere (determined by jump_targets), or (b) are deemed replaceable by the first pass.
|
|
19
18
|
"""
|
|
20
19
|
|
|
21
|
-
def __init__(self, node, jump_targets:
|
|
20
|
+
def __init__(self, node, jump_targets: set[tuple[int, int | None]]):
|
|
22
21
|
self.root = node
|
|
23
22
|
self._jump_targets = jump_targets
|
|
24
23
|
|
|
25
|
-
self._labels_to_remove:
|
|
26
|
-
self._new_jump_target:
|
|
24
|
+
self._labels_to_remove: set[ailment.Stmt.Label] = set()
|
|
25
|
+
self._new_jump_target: dict[tuple[int, int | None], tuple[int, int | None]] = {}
|
|
27
26
|
|
|
28
27
|
handlers0 = {
|
|
29
28
|
SequenceNode: self._handle_Sequence,
|
|
@@ -44,7 +43,7 @@ class RedundantLabelRemover:
|
|
|
44
43
|
|
|
45
44
|
def _handle_Sequence(self, node: SequenceNode, **kwargs):
|
|
46
45
|
# merge consecutive labels
|
|
47
|
-
last_label_addr:
|
|
46
|
+
last_label_addr: tuple[int, int | None] | None = None
|
|
48
47
|
for node_ in node.nodes:
|
|
49
48
|
if isinstance(node_, ailment.Block):
|
|
50
49
|
if node_.statements:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from itertools import count
|
|
2
2
|
from collections import defaultdict
|
|
3
3
|
import logging
|
|
4
|
-
from typing import List, Optional, Union
|
|
5
4
|
|
|
6
5
|
import networkx
|
|
7
6
|
|
|
@@ -59,7 +58,7 @@ class RegionIdentifier(Analysis):
|
|
|
59
58
|
|
|
60
59
|
self.region = None
|
|
61
60
|
self._start_node = None
|
|
62
|
-
self._loop_headers:
|
|
61
|
+
self._loop_headers: list | None = None
|
|
63
62
|
self.regions_by_block_addrs = []
|
|
64
63
|
self._largest_successor_tree_outside_loop = largest_successor_tree_outside_loop
|
|
65
64
|
self._force_loop_single_exit = force_loop_single_exit
|
|
@@ -102,7 +101,7 @@ class RegionIdentifier(Analysis):
|
|
|
102
101
|
# make regions into block address lists
|
|
103
102
|
self.regions_by_block_addrs = self._make_regions_by_block_addrs()
|
|
104
103
|
|
|
105
|
-
def _make_regions_by_block_addrs(self) ->
|
|
104
|
+
def _make_regions_by_block_addrs(self) -> list[list[int]]:
|
|
106
105
|
"""
|
|
107
106
|
Creates a list of addr lists representing each region without recursion. A single region is defined
|
|
108
107
|
as a set of only blocks, no Graphs containing nested regions. The list contains the address of each
|
|
@@ -190,7 +189,7 @@ class RegionIdentifier(Analysis):
|
|
|
190
189
|
else:
|
|
191
190
|
break
|
|
192
191
|
|
|
193
|
-
def _find_loop_headers(self, graph: networkx.DiGraph) ->
|
|
192
|
+
def _find_loop_headers(self, graph: networkx.DiGraph) -> list:
|
|
194
193
|
heads = {t for _, t in dfs_back_edges(graph, self._start_node)}
|
|
195
194
|
return GraphUtils.quasi_topological_sort_nodes(graph, heads)
|
|
196
195
|
|
|
@@ -1061,7 +1060,7 @@ class RegionIdentifier(Analysis):
|
|
|
1061
1060
|
assert node_mommy not in graph
|
|
1062
1061
|
assert node_kiddie not in graph
|
|
1063
1062
|
|
|
1064
|
-
def _ensure_jump_at_loop_exit_ends(self, node:
|
|
1063
|
+
def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
|
|
1065
1064
|
if isinstance(node, Block):
|
|
1066
1065
|
if not node.statements:
|
|
1067
1066
|
node.statements.append(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=no-self-use,arguments-renamed,isinstance-second-argument-not-valid-type
|
|
2
|
-
from typing import Optional
|
|
3
2
|
|
|
4
3
|
import ailment
|
|
5
4
|
import claripy
|
|
@@ -19,7 +18,7 @@ class CascadingConditionTransformer(SequenceWalker):
|
|
|
19
18
|
ConditionNode: self._handle_Condition,
|
|
20
19
|
}
|
|
21
20
|
super().__init__(handlers)
|
|
22
|
-
self.cascading_if_node:
|
|
21
|
+
self.cascading_if_node: CascadingConditionNode | None = None
|
|
23
22
|
|
|
24
23
|
self.walk(node)
|
|
25
24
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# pylint:disable=missing-class-docstring,unused-argument
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from typing import Optional, Any,
|
|
3
|
+
from typing import Optional, Any, DefaultDict, TYPE_CHECKING
|
|
4
|
+
from collections.abc import Iterable
|
|
4
5
|
|
|
5
6
|
import ailment
|
|
6
7
|
from ailment import Expression, Block, AILBlockWalker
|
|
@@ -95,7 +96,7 @@ class ConditionLocation(LocationBase):
|
|
|
95
96
|
"case_idx",
|
|
96
97
|
)
|
|
97
98
|
|
|
98
|
-
def __init__(self, cond_node_addr, case_idx:
|
|
99
|
+
def __init__(self, cond_node_addr, case_idx: int | None = None):
|
|
99
100
|
self.node_addr = cond_node_addr
|
|
100
101
|
self.case_idx = case_idx
|
|
101
102
|
|
|
@@ -139,7 +140,7 @@ class MultiStatementExpressionAssignmentFinder(AILBlockWalker):
|
|
|
139
140
|
self._stmt_handler = stmt_handler
|
|
140
141
|
|
|
141
142
|
def _handle_MultiStatementExpression(
|
|
142
|
-
self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block:
|
|
143
|
+
self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Block | None
|
|
143
144
|
):
|
|
144
145
|
for idx, stmt_ in enumerate(expr.stmts):
|
|
145
146
|
self._stmt_handler(idx, stmt_, block)
|
|
@@ -174,11 +175,11 @@ class ExpressionUseFinder(AILBlockWalker):
|
|
|
174
175
|
|
|
175
176
|
def __init__(self):
|
|
176
177
|
super().__init__()
|
|
177
|
-
self.uses: DefaultDict[SimVariable,
|
|
178
|
+
self.uses: DefaultDict[SimVariable, set[tuple[Expression, ExpressionLocation | None]]] = defaultdict(set)
|
|
178
179
|
self.has_load = False
|
|
179
180
|
|
|
180
181
|
def _handle_expr(
|
|
181
|
-
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt:
|
|
182
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
182
183
|
) -> Any:
|
|
183
184
|
if isinstance(expr, ailment.Register) and expr.variable is not None:
|
|
184
185
|
if not (isinstance(stmt, ailment.Stmt.Assignment) and stmt.dst is expr):
|
|
@@ -189,9 +190,7 @@ class ExpressionUseFinder(AILBlockWalker):
|
|
|
189
190
|
return None
|
|
190
191
|
return super()._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
|
|
191
192
|
|
|
192
|
-
def _handle_Load(
|
|
193
|
-
self, expr_idx: int, expr: ailment.Expr.Load, stmt_idx: int, stmt: Statement, block: Optional[Block]
|
|
194
|
-
):
|
|
193
|
+
def _handle_Load(self, expr_idx: int, expr: ailment.Expr.Load, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
195
194
|
self.has_load = True
|
|
196
195
|
return super()._handle_Load(expr_idx, expr, stmt_idx, stmt, block)
|
|
197
196
|
|
|
@@ -213,8 +212,8 @@ class ExpressionCounter(SequenceWalker):
|
|
|
213
212
|
# each element in the set is a tuple of (source of the assignment statement, a tuple of unified variables that
|
|
214
213
|
# the current assignment depends on, StatementLocation of the assignment statement, a Boolean variable that
|
|
215
214
|
# indicates if ExpressionUseFinder has succeeded or not)
|
|
216
|
-
self.assignments: DefaultDict[Any,
|
|
217
|
-
self.uses:
|
|
215
|
+
self.assignments: DefaultDict[Any, set[tuple]] = defaultdict(set)
|
|
216
|
+
self.uses: dict[SimVariable, set[tuple[Expression, LocationBase | None]]] = {}
|
|
218
217
|
self._variable_manager: "VariableManagerInternal" = variable_manager
|
|
219
218
|
|
|
220
219
|
super().__init__(handlers)
|
|
@@ -227,7 +226,7 @@ class ExpressionCounter(SequenceWalker):
|
|
|
227
226
|
|
|
228
227
|
return self._variable_manager.unified_variable(v)
|
|
229
228
|
|
|
230
|
-
def _handle_Statement(self, idx: int, stmt: ailment.Stmt, node:
|
|
229
|
+
def _handle_Statement(self, idx: int, stmt: ailment.Stmt, node: ailment.Block | LoopNode):
|
|
231
230
|
if isinstance(stmt, ailment.Stmt.Assignment):
|
|
232
231
|
if isinstance(stmt.dst, ailment.Expr.Register) and stmt.dst.variable is not None:
|
|
233
232
|
u = self._u(stmt.dst.variable)
|
|
@@ -331,7 +330,7 @@ class ExpressionCounter(SequenceWalker):
|
|
|
331
330
|
|
|
332
331
|
|
|
333
332
|
class ExpressionReplacer(AILBlockWalker):
|
|
334
|
-
def __init__(self, assignments:
|
|
333
|
+
def __init__(self, assignments: dict, uses: dict, variable_manager):
|
|
335
334
|
super().__init__()
|
|
336
335
|
self._assignments = assignments
|
|
337
336
|
self._uses = uses
|
|
@@ -344,7 +343,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
344
343
|
return self._variable_manager.unified_variable(v)
|
|
345
344
|
|
|
346
345
|
def _handle_MultiStatementExpression(
|
|
347
|
-
self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block:
|
|
346
|
+
self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Block | None
|
|
348
347
|
):
|
|
349
348
|
changed = False
|
|
350
349
|
new_statements = []
|
|
@@ -385,7 +384,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
385
384
|
return expr_
|
|
386
385
|
return None
|
|
387
386
|
|
|
388
|
-
def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block:
|
|
387
|
+
def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Block | None):
|
|
389
388
|
# override the base handler and make sure we do not replace .dst with a Call expression or an ITE expression
|
|
390
389
|
changed = False
|
|
391
390
|
|
|
@@ -410,7 +409,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
410
409
|
return None
|
|
411
410
|
|
|
412
411
|
def _handle_expr(
|
|
413
|
-
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt:
|
|
412
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
414
413
|
) -> Any:
|
|
415
414
|
if isinstance(expr, ailment.Register) and expr.variable is not None:
|
|
416
415
|
unified_var = self._u(expr.variable)
|
|
@@ -421,7 +420,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
421
420
|
|
|
422
421
|
|
|
423
422
|
class ExpressionFolder(SequenceWalker):
|
|
424
|
-
def __init__(self, assignments:
|
|
423
|
+
def __init__(self, assignments: dict, uses: dict, node, variable_manager):
|
|
425
424
|
handlers = {
|
|
426
425
|
ailment.Block: self._handle_Block,
|
|
427
426
|
ConditionNode: self._handle_Condition,
|
|
@@ -530,7 +529,7 @@ class StoreStatementFinder(SequenceWalker):
|
|
|
530
529
|
This class overrides _handle_Sequence() and _handle_MultiNode() to ensure they traverse nodes from top to bottom.
|
|
531
530
|
"""
|
|
532
531
|
|
|
533
|
-
def __init__(self, node, intervals: Iterable[
|
|
532
|
+
def __init__(self, node, intervals: Iterable[tuple[StatementLocation, LocationBase]]):
|
|
534
533
|
handlers = {
|
|
535
534
|
ConditionNode: self._handle_Condition,
|
|
536
535
|
CascadingConditionNode: self._handle_CascadingCondition,
|
|
@@ -540,9 +539,9 @@ class StoreStatementFinder(SequenceWalker):
|
|
|
540
539
|
|
|
541
540
|
self._intervals = intervals
|
|
542
541
|
|
|
543
|
-
self._start_to_ends: DefaultDict[StatementLocation,
|
|
544
|
-
self._end_to_starts: DefaultDict[LocationBase,
|
|
545
|
-
self.interval_to_hasstore:
|
|
542
|
+
self._start_to_ends: DefaultDict[StatementLocation, set[LocationBase]] = defaultdict(set)
|
|
543
|
+
self._end_to_starts: DefaultDict[LocationBase, set[StatementLocation]] = defaultdict(set)
|
|
544
|
+
self.interval_to_hasstore: dict[tuple[StatementLocation, StatementLocation], bool] = {}
|
|
546
545
|
for start, end in intervals:
|
|
547
546
|
self._start_to_ends[start].add(end)
|
|
548
547
|
self._end_to_starts[end].add(start)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=unused-argument,arguments-differ
|
|
2
|
-
from typing import Set, Union
|
|
3
2
|
import logging
|
|
4
3
|
|
|
5
4
|
import ailment
|
|
@@ -47,7 +46,7 @@ class GotoSimplifier(SequenceWalker):
|
|
|
47
46
|
self.irreducible_gotos = set()
|
|
48
47
|
|
|
49
48
|
super().__init__(handlers)
|
|
50
|
-
self._node_addrs:
|
|
49
|
+
self._node_addrs: set[int] = NodeAddressFinder(node).addrs
|
|
51
50
|
|
|
52
51
|
self.walk(node)
|
|
53
52
|
|
|
@@ -156,7 +155,7 @@ class GotoSimplifier(SequenceWalker):
|
|
|
156
155
|
self._handle_irreducible_goto(block, last_stmt, branch_target=False)
|
|
157
156
|
|
|
158
157
|
def _handle_irreducible_goto(
|
|
159
|
-
self, block, goto_stmt:
|
|
158
|
+
self, block, goto_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump, branch_target=None
|
|
160
159
|
):
|
|
161
160
|
if not self._function:
|
|
162
161
|
l.debug("Unable to store a goto at %#x because simplifier is kb or functionless", block.addr)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# pylint:disable=unused-argument,arguments-differ
|
|
2
2
|
from collections import defaultdict
|
|
3
|
-
from typing import Dict, List
|
|
4
3
|
|
|
5
4
|
import ailment
|
|
6
5
|
|
|
@@ -36,7 +35,7 @@ class LoopSimplifier(SequenceWalker):
|
|
|
36
35
|
|
|
37
36
|
super().__init__(handlers)
|
|
38
37
|
self.functions = functions
|
|
39
|
-
self.continue_preludes:
|
|
38
|
+
self.continue_preludes: dict[LoopNode, list[ailment.Block]] = defaultdict(list)
|
|
40
39
|
self.walk(node)
|
|
41
40
|
|
|
42
41
|
@staticmethod
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=unused-argument,arguments-differ
|
|
2
|
-
from typing import Set
|
|
3
2
|
|
|
4
3
|
import ailment
|
|
5
4
|
|
|
@@ -16,7 +15,7 @@ class NodeAddressFinder(SequenceWalker):
|
|
|
16
15
|
ailment.Block: self._handle_Block,
|
|
17
16
|
}
|
|
18
17
|
super().__init__(handlers=handlers)
|
|
19
|
-
self.addrs:
|
|
18
|
+
self.addrs: set[int] = set()
|
|
20
19
|
|
|
21
20
|
self.walk(node)
|
|
22
21
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import ailment
|
|
4
2
|
|
|
5
3
|
from ..goto_manager import GotoManager
|
|
@@ -31,7 +29,7 @@ class RegionSimplifier(Analysis):
|
|
|
31
29
|
self._simplify_switches = simplify_switches
|
|
32
30
|
self._should_simplify_ifelses = simplify_ifelse
|
|
33
31
|
|
|
34
|
-
self.goto_manager:
|
|
32
|
+
self.goto_manager: GotoManager | None = None
|
|
35
33
|
self.result = None
|
|
36
34
|
|
|
37
35
|
self._simplify()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pylint:disable=no-self-use,arguments-renamed
|
|
2
2
|
import enum
|
|
3
|
-
from typing import DefaultDict, Any
|
|
3
|
+
from typing import DefaultDict, Any
|
|
4
4
|
from collections import OrderedDict, defaultdict
|
|
5
5
|
|
|
6
6
|
import ailment
|
|
@@ -36,7 +36,7 @@ class ConditionalRegion:
|
|
|
36
36
|
"parent",
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
def __init__(self, variable, op: CmpOp, value: int, node:
|
|
39
|
+
def __init__(self, variable, op: CmpOp, value: int, node: ConditionNode | ailment.Block, parent=None):
|
|
40
40
|
self.variable = variable
|
|
41
41
|
self.op = op
|
|
42
42
|
self.value = value
|
|
@@ -80,8 +80,8 @@ class SwitchClusterFinder(SequenceWalker):
|
|
|
80
80
|
}
|
|
81
81
|
super().__init__(handlers)
|
|
82
82
|
|
|
83
|
-
self.var2condnodes: DefaultDict[Any,
|
|
84
|
-
self.var2switches: DefaultDict[Any,
|
|
83
|
+
self.var2condnodes: DefaultDict[Any, list[ConditionalRegion]] = defaultdict(list)
|
|
84
|
+
self.var2switches: DefaultDict[Any, list[SwitchCaseRegion]] = defaultdict(list)
|
|
85
85
|
|
|
86
86
|
self.walk(node)
|
|
87
87
|
|
|
@@ -103,7 +103,7 @@ class SwitchClusterFinder(SequenceWalker):
|
|
|
103
103
|
self.var2switches[variable].append(scr)
|
|
104
104
|
return super()._handle_SwitchCase(node, parent=parent, **kwargs)
|
|
105
105
|
|
|
106
|
-
def _process_condition(self, cond: ailment.Expr.Expression, node:
|
|
106
|
+
def _process_condition(self, cond: ailment.Expr.Expression, node: ConditionNode | ailment.Block, parent):
|
|
107
107
|
negated = False
|
|
108
108
|
if isinstance(cond, ailment.Expr.UnaryOp) and cond.op == "Not":
|
|
109
109
|
negated = True
|
|
@@ -173,7 +173,7 @@ class SwitchClusterReplacer(SequenceWalker):
|
|
|
173
173
|
return super()._handle_Condition(node, **kwargs)
|
|
174
174
|
|
|
175
175
|
|
|
176
|
-
def is_simple_jump_node(node, case_addrs, targets:
|
|
176
|
+
def is_simple_jump_node(node, case_addrs, targets: set[int] | None = None) -> bool:
|
|
177
177
|
if isinstance(node, (SequenceNode, MultiNode)):
|
|
178
178
|
return all(is_simple_jump_node(nn, case_addrs) for nn in node.nodes)
|
|
179
179
|
if isinstance(node, ailment.Block):
|
|
@@ -213,7 +213,7 @@ def is_simple_jump_node(node, case_addrs, targets: Optional[Set[int]] = None) ->
|
|
|
213
213
|
return False
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
def filter_cond_regions(cond_regions:
|
|
216
|
+
def filter_cond_regions(cond_regions: list[ConditionalRegion], case_addrs: set[int]) -> list[ConditionalRegion]:
|
|
217
217
|
"""
|
|
218
218
|
Remove all conditional regions that cannot be merged into switch(es).
|
|
219
219
|
"""
|
|
@@ -242,8 +242,8 @@ def filter_cond_regions(cond_regions: List[ConditionalRegion], case_addrs: Set[i
|
|
|
242
242
|
|
|
243
243
|
|
|
244
244
|
def update_switch_case_list(
|
|
245
|
-
cases:
|
|
246
|
-
old_case_id:
|
|
245
|
+
cases: list[tuple[int | tuple[int, ...], SequenceNode]],
|
|
246
|
+
old_case_id: int | tuple[int, ...],
|
|
247
247
|
new_case_id: int,
|
|
248
248
|
) -> None:
|
|
249
249
|
"""
|
|
@@ -265,7 +265,7 @@ def update_switch_case_list(
|
|
|
265
265
|
|
|
266
266
|
|
|
267
267
|
def simplify_switch_clusters(
|
|
268
|
-
region, var2condnodes:
|
|
268
|
+
region, var2condnodes: dict[Any, list[ConditionalRegion]], var2switches: dict[Any, list[SwitchCaseRegion]]
|
|
269
269
|
):
|
|
270
270
|
"""
|
|
271
271
|
Identify switch clusters and simplify each of them.
|
|
@@ -284,7 +284,7 @@ def simplify_switch_clusters(
|
|
|
284
284
|
continue
|
|
285
285
|
|
|
286
286
|
# each switch region belongs to a conditional region
|
|
287
|
-
switch_region_to_parent_region:
|
|
287
|
+
switch_region_to_parent_region: dict[SwitchCaseRegion, tuple[ConditionalRegion, str]] = {}
|
|
288
288
|
used_condnodes_and_branch = set()
|
|
289
289
|
for r in switch_regions:
|
|
290
290
|
for cr in cond_regions:
|
|
@@ -337,20 +337,20 @@ def simplify_switch_clusters(
|
|
|
337
337
|
used_condnodes = list(condnode for condnode, _ in used_condnodes_and_branch)
|
|
338
338
|
|
|
339
339
|
# collect addresses for all case nodes
|
|
340
|
-
case_addr_to_case_id:
|
|
340
|
+
case_addr_to_case_id: dict[int, int | tuple[int, ...] | str] = {}
|
|
341
341
|
for sr in switch_regions:
|
|
342
342
|
for case_id, case_node in sr.node.cases.items():
|
|
343
343
|
case_addr_to_case_id[case_node.addr] = case_id
|
|
344
344
|
if sr.node.default_node is not None:
|
|
345
345
|
case_addr_to_case_id[sr.node.default_node.addr] = "default"
|
|
346
|
-
case_addrs:
|
|
346
|
+
case_addrs: set[int] = set(case_addr_to_case_id)
|
|
347
347
|
|
|
348
348
|
# filter cond_regions
|
|
349
349
|
mergeable_cond_regions = filter_cond_regions(cond_regions, case_addrs)
|
|
350
350
|
|
|
351
351
|
# list all unmatched conditional nodes
|
|
352
|
-
standalone_condnodes:
|
|
353
|
-
standalone_condjumps:
|
|
352
|
+
standalone_condnodes: list[tuple[ConditionalRegion, str]] = []
|
|
353
|
+
standalone_condjumps: list[ConditionalRegion] = []
|
|
354
354
|
for cr in mergeable_cond_regions:
|
|
355
355
|
if isinstance(cr.node, ConditionNode):
|
|
356
356
|
if cr.node.true_node is not None and (cr, "true") not in used_condnodes_and_branch:
|
|
@@ -487,7 +487,7 @@ def simplify_switch_clusters(
|
|
|
487
487
|
continue
|
|
488
488
|
|
|
489
489
|
|
|
490
|
-
def simplify_lowered_switches(region: SequenceNode, var2condnodes:
|
|
490
|
+
def simplify_lowered_switches(region: SequenceNode, var2condnodes: dict[Any, list[ConditionalRegion]], functions):
|
|
491
491
|
"""
|
|
492
492
|
Identify a lowered switch and simplify it into a switch-case if possible.
|
|
493
493
|
|
|
@@ -522,8 +522,8 @@ def simplify_lowered_switches_core(
|
|
|
522
522
|
return False
|
|
523
523
|
|
|
524
524
|
caseno_to_node = {}
|
|
525
|
-
default_node_candidates:
|
|
526
|
-
stack:
|
|
525
|
+
default_node_candidates: list[tuple[BaseNode, BaseNode]] = [] # parent to default node candidate
|
|
526
|
+
stack: list[(ConditionNode, int, int)] = [(outermost_node, 0, 0xFFFF_FFFF_FFFF_FFFF)]
|
|
527
527
|
while stack:
|
|
528
528
|
node, min_, max_ = stack.pop(0)
|
|
529
529
|
if node not in node_to_condnode:
|
|
@@ -632,7 +632,7 @@ class FindFirstNodeInSet(SequenceWalker):
|
|
|
632
632
|
Find the first node out of a set of node appearing in a SequenceNode (and its tree).
|
|
633
633
|
"""
|
|
634
634
|
|
|
635
|
-
def __init__(self, node_set:
|
|
635
|
+
def __init__(self, node_set: set[BaseNode]):
|
|
636
636
|
super().__init__(update_seqnode_in_place=False, force_forward_scan=True)
|
|
637
637
|
self.node_set = node_set
|
|
638
638
|
self.first_node = None
|