angr 9.2.102__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 +39 -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.102.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
- {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/RECORD +240 -237
- {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
- {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
- {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
- {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# decompilation options
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import Callable
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
|
|
5
5
|
from .structuring import structurer_class_from_name
|
|
@@ -22,8 +22,8 @@ class DecompilationOption:
|
|
|
22
22
|
category="General",
|
|
23
23
|
default_value=None,
|
|
24
24
|
clears_cache=True,
|
|
25
|
-
candidate_values:
|
|
26
|
-
convert:
|
|
25
|
+
candidate_values: list | None = None,
|
|
26
|
+
convert: Callable | None = None,
|
|
27
27
|
):
|
|
28
28
|
self.NAME = name
|
|
29
29
|
self.DESCRIPTION = description
|
|
@@ -267,7 +267,7 @@ for o in options:
|
|
|
267
267
|
#
|
|
268
268
|
|
|
269
269
|
|
|
270
|
-
def get_structurer_option() ->
|
|
270
|
+
def get_structurer_option() -> DecompilationOption | None:
|
|
271
271
|
for opt in options:
|
|
272
272
|
if opt.cls == "recursive_structurer" and opt.param == "structurer_cls":
|
|
273
273
|
return opt
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# pylint:disable=unused-import
|
|
2
2
|
import logging
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Optional, Union, Any, TYPE_CHECKING
|
|
5
|
+
from collections.abc import Iterable
|
|
5
6
|
|
|
6
7
|
import networkx
|
|
7
8
|
from cle import SymbolType
|
|
@@ -33,7 +34,7 @@ if TYPE_CHECKING:
|
|
|
33
34
|
l = logging.getLogger(name=__name__)
|
|
34
35
|
|
|
35
36
|
_PEEPHOLE_OPTIMIZATIONS_TYPE = Optional[
|
|
36
|
-
Iterable[Union[
|
|
37
|
+
Iterable[Union[type["PeepholeOptimizationStmtBase"], type["PeepholeOptimizationExprBase"]]]
|
|
37
38
|
]
|
|
38
39
|
|
|
39
40
|
|
|
@@ -47,14 +48,14 @@ class Decompiler(Analysis):
|
|
|
47
48
|
|
|
48
49
|
def __init__(
|
|
49
50
|
self,
|
|
50
|
-
func:
|
|
51
|
-
cfg:
|
|
51
|
+
func: Function | str | int,
|
|
52
|
+
cfg: Union["CFGFast", "CFGModel"] | None = None,
|
|
52
53
|
options=None,
|
|
53
54
|
optimization_passes=None,
|
|
54
55
|
sp_tracker_track_memory=True,
|
|
55
56
|
variable_kb=None,
|
|
56
57
|
peephole_optimizations: _PEEPHOLE_OPTIMIZATIONS_TYPE = None,
|
|
57
|
-
vars_must_struct:
|
|
58
|
+
vars_must_struct: set[str] | None = None,
|
|
58
59
|
flavor="pseudocode",
|
|
59
60
|
expr_comments=None,
|
|
60
61
|
stmt_comments=None,
|
|
@@ -62,6 +63,7 @@ class Decompiler(Analysis):
|
|
|
62
63
|
binop_operators=None,
|
|
63
64
|
decompile=True,
|
|
64
65
|
regen_clinic=True,
|
|
66
|
+
inline_functions=frozenset(),
|
|
65
67
|
update_memory_data: bool = True,
|
|
66
68
|
generate_code: bool = True,
|
|
67
69
|
):
|
|
@@ -87,14 +89,15 @@ class Decompiler(Analysis):
|
|
|
87
89
|
self._regen_clinic = regen_clinic
|
|
88
90
|
self._update_memory_data = update_memory_data
|
|
89
91
|
self._generate_code = generate_code
|
|
92
|
+
self._inline_functions = inline_functions
|
|
90
93
|
|
|
91
94
|
self.clinic = None # mostly for debugging purposes
|
|
92
95
|
self.codegen: Optional["CStructuredCodeGenerator"] = None
|
|
93
|
-
self.cache:
|
|
96
|
+
self.cache: DecompilationCache | None = None
|
|
94
97
|
self.options_by_class = None
|
|
95
98
|
self.seq_node: Optional["SequenceNode"] = None
|
|
96
|
-
self.unoptimized_ail_graph:
|
|
97
|
-
self.ail_graph:
|
|
99
|
+
self.unoptimized_ail_graph: networkx.DiGraph | None = None
|
|
100
|
+
self.ail_graph: networkx.DiGraph | None = None
|
|
98
101
|
|
|
99
102
|
if decompile:
|
|
100
103
|
self._decompile()
|
|
@@ -171,6 +174,7 @@ class Decompiler(Analysis):
|
|
|
171
174
|
must_struct=self._vars_must_struct,
|
|
172
175
|
cache=cache,
|
|
173
176
|
progress_callback=progress_callback,
|
|
177
|
+
inline_functions=self._inline_functions,
|
|
174
178
|
**self.options_to_params(self.options_by_class["clinic"]),
|
|
175
179
|
)
|
|
176
180
|
else:
|
|
@@ -295,8 +299,8 @@ class Decompiler(Analysis):
|
|
|
295
299
|
:param reaching_defenitions: ReachingDefenitionAnalysis
|
|
296
300
|
:return: The possibly new AIL DiGraph and RegionIdentifier
|
|
297
301
|
"""
|
|
298
|
-
addr_and_idx_to_blocks:
|
|
299
|
-
addr_to_blocks:
|
|
302
|
+
addr_and_idx_to_blocks: dict[tuple[int, int | None], ailment.Block] = {}
|
|
303
|
+
addr_to_blocks: dict[int, set[ailment.Block]] = defaultdict(set)
|
|
300
304
|
|
|
301
305
|
# update blocks_map to allow node_addr to node lookup
|
|
302
306
|
def _updatedict_handler(node):
|
|
@@ -346,8 +350,8 @@ class Decompiler(Analysis):
|
|
|
346
350
|
:param reaching_defenitions: ReachingDefenitionAnalysis
|
|
347
351
|
:return: The possibly new AIL DiGraph and RegionIdentifier
|
|
348
352
|
"""
|
|
349
|
-
addr_and_idx_to_blocks:
|
|
350
|
-
addr_to_blocks:
|
|
353
|
+
addr_and_idx_to_blocks: dict[tuple[int, int | None], ailment.Block] = {}
|
|
354
|
+
addr_to_blocks: dict[int, set[ailment.Block]] = defaultdict(set)
|
|
351
355
|
|
|
352
356
|
# update blocks_map to allow node_addr to node lookup
|
|
353
357
|
def _updatedict_handler(node):
|
|
@@ -415,7 +419,7 @@ class Decompiler(Analysis):
|
|
|
415
419
|
SimMemoryVariable(symbol.rebased_addr, 1, name=symbol.name, ident=ident),
|
|
416
420
|
)
|
|
417
421
|
|
|
418
|
-
def reflow_variable_types(self, type_constraints:
|
|
422
|
+
def reflow_variable_types(self, type_constraints: set, func_typevar, var_to_typevar: dict, codegen):
|
|
419
423
|
"""
|
|
420
424
|
Re-run type inference on an existing variable recovery result, then rerun codegen to generate new results.
|
|
421
425
|
|
|
@@ -485,7 +489,7 @@ class Decompiler(Analysis):
|
|
|
485
489
|
return codegen
|
|
486
490
|
|
|
487
491
|
def find_data_references_and_update_memory_data(self, seq_node: "SequenceNode"):
|
|
488
|
-
const_values:
|
|
492
|
+
const_values: set[int] = set()
|
|
489
493
|
|
|
490
494
|
def _handle_Const(expr_idx: int, expr: ailment.Expr.Const, *args, **kwargs): # pylint:disable=unused-argument
|
|
491
495
|
const_values.add(expr.value)
|
|
@@ -520,7 +524,7 @@ class Decompiler(Analysis):
|
|
|
520
524
|
)
|
|
521
525
|
|
|
522
526
|
@staticmethod
|
|
523
|
-
def options_to_params(options:
|
|
527
|
+
def options_to_params(options: list[tuple[DecompilationOption, Any]]) -> dict[str, Any]:
|
|
524
528
|
"""
|
|
525
529
|
Convert decompilation options to a dict of params.
|
|
526
530
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any, DefaultDict, TYPE_CHECKING
|
|
2
|
+
from collections.abc import Iterable
|
|
2
3
|
from collections import defaultdict
|
|
3
4
|
|
|
4
5
|
from ailment.expression import Expression, Register
|
|
@@ -22,7 +23,7 @@ class SingleExpressionCounter(AILBlockWalkerBase):
|
|
|
22
23
|
self.walk_statement(stmt)
|
|
23
24
|
|
|
24
25
|
def _handle_expr(
|
|
25
|
-
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt:
|
|
26
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
26
27
|
) -> Any:
|
|
27
28
|
if expr == self.subexpr:
|
|
28
29
|
self.count += 1
|
|
@@ -34,9 +35,9 @@ class RegisterExpressionCounter(AILBlockWalkerBase):
|
|
|
34
35
|
Count the occurrence of all register expressions in expr
|
|
35
36
|
"""
|
|
36
37
|
|
|
37
|
-
def __init__(self, expr_or_stmt:
|
|
38
|
+
def __init__(self, expr_or_stmt: Expression | Statement):
|
|
38
39
|
super().__init__()
|
|
39
|
-
self.counts: DefaultDict[
|
|
40
|
+
self.counts: DefaultDict[tuple[int, int], int] = defaultdict(int)
|
|
40
41
|
if isinstance(expr_or_stmt, Expression):
|
|
41
42
|
self.walk_expression(expr_or_stmt)
|
|
42
43
|
elif isinstance(expr_or_stmt, Statement):
|
|
@@ -44,7 +45,7 @@ class RegisterExpressionCounter(AILBlockWalkerBase):
|
|
|
44
45
|
else:
|
|
45
46
|
raise TypeError(f"Unsupported argument type {type(expr_or_stmt)}")
|
|
46
47
|
|
|
47
|
-
def _handle_Register(self, expr_idx: int, expr: Register, stmt_idx: int, stmt: Statement, block:
|
|
48
|
+
def _handle_Register(self, expr_idx: int, expr: Register, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
48
49
|
self.counts[expr.reg_offset, expr.size] += 1
|
|
49
50
|
|
|
50
51
|
|
|
@@ -53,10 +54,10 @@ class OperatorCounter(AILBlockWalkerBase):
|
|
|
53
54
|
Count the occurrence of a given expression operator.
|
|
54
55
|
"""
|
|
55
56
|
|
|
56
|
-
def __init__(self, operator:
|
|
57
|
+
def __init__(self, operator: str | Iterable[str], expr_or_stmt: Expression | Statement):
|
|
57
58
|
super().__init__()
|
|
58
59
|
self.count = 0
|
|
59
|
-
self.operators:
|
|
60
|
+
self.operators: set[str] = {operator} if isinstance(operator, str) else set(operator)
|
|
60
61
|
if isinstance(expr_or_stmt, Expression):
|
|
61
62
|
self.walk_expression(expr_or_stmt)
|
|
62
63
|
elif isinstance(expr_or_stmt, Statement):
|
|
@@ -64,12 +65,12 @@ class OperatorCounter(AILBlockWalkerBase):
|
|
|
64
65
|
else:
|
|
65
66
|
raise TypeError(f"Unsupported argument type {type(expr_or_stmt)}")
|
|
66
67
|
|
|
67
|
-
def _handle_BinaryOp(self, expr_idx: int, expr: "BinaryOp", stmt_idx: int, stmt: Statement, block:
|
|
68
|
+
def _handle_BinaryOp(self, expr_idx: int, expr: "BinaryOp", stmt_idx: int, stmt: Statement, block: Block | None):
|
|
68
69
|
if expr.op in self.operators:
|
|
69
70
|
self.count += 1
|
|
70
71
|
return super()._handle_BinaryOp(expr_idx, expr, stmt_idx, stmt, block)
|
|
71
72
|
|
|
72
|
-
def _handle_UnaryOp(self, expr_idx: int, expr: "UnaryOp", stmt_idx: int, stmt: Statement, block:
|
|
73
|
+
def _handle_UnaryOp(self, expr_idx: int, expr: "UnaryOp", stmt_idx: int, stmt: Statement, block: Block | None):
|
|
73
74
|
if expr.op in self.operators:
|
|
74
75
|
self.count += 1
|
|
75
76
|
return super()._handle_UnaryOp(expr_idx, expr, stmt_idx, stmt, block)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Set
|
|
2
|
-
|
|
3
1
|
import ailment
|
|
4
2
|
|
|
5
3
|
|
|
@@ -40,7 +38,7 @@ class GotoManager:
|
|
|
40
38
|
|
|
41
39
|
def __init__(self, func, gotos=None):
|
|
42
40
|
self.func = func
|
|
43
|
-
self.gotos:
|
|
41
|
+
self.gotos: set[Goto] = gotos or set()
|
|
44
42
|
|
|
45
43
|
self._gotos_by_addr = None
|
|
46
44
|
|
|
@@ -50,7 +48,7 @@ class GotoManager:
|
|
|
50
48
|
def __repr__(self):
|
|
51
49
|
return self.__str__()
|
|
52
50
|
|
|
53
|
-
def gotos_in_block(self, block: ailment.Block) ->
|
|
51
|
+
def gotos_in_block(self, block: ailment.Block) -> set[Goto]:
|
|
54
52
|
gotos_found = set()
|
|
55
53
|
for goto in self.gotos:
|
|
56
54
|
if goto.src_addr == block.addr:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
|
|
5
5
|
import networkx
|
|
@@ -37,10 +37,10 @@ class GraphRegion:
|
|
|
37
37
|
self,
|
|
38
38
|
head,
|
|
39
39
|
graph,
|
|
40
|
-
successors:
|
|
41
|
-
graph_with_successors:
|
|
40
|
+
successors: set | None,
|
|
41
|
+
graph_with_successors: networkx.DiGraph | None,
|
|
42
42
|
cyclic,
|
|
43
|
-
full_graph:
|
|
43
|
+
full_graph: networkx.DiGraph | None,
|
|
44
44
|
cyclic_ancestor: bool = False,
|
|
45
45
|
):
|
|
46
46
|
self.head = head
|
|
@@ -61,7 +61,7 @@ class GraphRegion:
|
|
|
61
61
|
self._replaced_regions = {}
|
|
62
62
|
|
|
63
63
|
def __repr__(self):
|
|
64
|
-
addrs:
|
|
64
|
+
addrs: list[int] = []
|
|
65
65
|
s = ""
|
|
66
66
|
if self.graph is None:
|
|
67
67
|
# only head is available
|
|
@@ -197,7 +197,7 @@ class GraphRegion:
|
|
|
197
197
|
sub_region: "GraphRegion",
|
|
198
198
|
updated_sub_region: "GraphRegion",
|
|
199
199
|
replace_with,
|
|
200
|
-
virtualized_edges:
|
|
200
|
+
virtualized_edges: set[tuple[Any, Any]],
|
|
201
201
|
):
|
|
202
202
|
if sub_region not in self.graph:
|
|
203
203
|
l.error("The sub-region to replace must be in the current region. Note that this method is not recursive.")
|
|
@@ -299,7 +299,7 @@ class GraphRegion:
|
|
|
299
299
|
)
|
|
300
300
|
|
|
301
301
|
@staticmethod
|
|
302
|
-
def _replace_node_in_graph(graph: networkx.DiGraph, node, replace_with, removed_edges:
|
|
302
|
+
def _replace_node_in_graph(graph: networkx.DiGraph, node, replace_with, removed_edges: set):
|
|
303
303
|
in_edges = [(src, dst) for src, dst in graph.in_edges(node) if (src, dst) not in removed_edges]
|
|
304
304
|
out_edges = [(src, dst) for src, dst in graph.out_edges(node) if (src, dst) not in removed_edges]
|
|
305
305
|
|
|
@@ -323,8 +323,8 @@ class GraphRegion:
|
|
|
323
323
|
def _replace_node_in_graph_with_subgraph(
|
|
324
324
|
self,
|
|
325
325
|
graph: networkx.DiGraph,
|
|
326
|
-
known_successors:
|
|
327
|
-
reference_full_graph:
|
|
326
|
+
known_successors: list | None,
|
|
327
|
+
reference_full_graph: networkx.DiGraph | None,
|
|
328
328
|
node,
|
|
329
329
|
sub_graph: networkx.DiGraph,
|
|
330
330
|
sub_graph_head,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=unused-argument
|
|
2
|
-
from typing import Set, Tuple, Optional
|
|
3
2
|
|
|
4
3
|
import ailment
|
|
5
4
|
|
|
@@ -13,7 +12,7 @@ class JumpTargetCollector:
|
|
|
13
12
|
|
|
14
13
|
def __init__(self, node):
|
|
15
14
|
self.root = node
|
|
16
|
-
self.jump_targets:
|
|
15
|
+
self.jump_targets: set[tuple[int, int | None]] = set()
|
|
17
16
|
|
|
18
17
|
handlers = {
|
|
19
18
|
ailment.Block: self._handle_Block,
|
|
@@ -17,6 +17,7 @@ from .return_duplicator_low import ReturnDuplicatorLow
|
|
|
17
17
|
from .return_duplicator_high import ReturnDuplicatorHigh
|
|
18
18
|
from .const_derefs import ConstantDereferencesSimplifier
|
|
19
19
|
from .register_save_area_simplifier import RegisterSaveAreaSimplifier
|
|
20
|
+
from .spilled_register_finder import SpilledRegisterFinder
|
|
20
21
|
from .ret_addr_save_simplifier import RetAddrSaveSimplifier
|
|
21
22
|
from .x86_gcc_getpc_simplifier import X86GccGetPcSimplifier
|
|
22
23
|
from .flip_boolean_cmp import FlipBooleanCmp
|
|
@@ -25,6 +26,7 @@ from .win_stack_canary_simplifier import WinStackCanarySimplifier
|
|
|
25
26
|
from .cross_jump_reverter import CrossJumpReverter
|
|
26
27
|
from .code_motion import CodeMotionOptimization
|
|
27
28
|
from .switch_default_case_duplicator import SwitchDefaultCaseDuplicator
|
|
29
|
+
from .deadblock_remover import DeadblockRemover
|
|
28
30
|
from .inlined_string_transformation_simplifier import InlinedStringTransformationSimplifier
|
|
29
31
|
|
|
30
32
|
# order matters!
|
|
@@ -43,6 +45,7 @@ _all_optimization_passes = [
|
|
|
43
45
|
(ITEExprConverter, True),
|
|
44
46
|
(ExprOpSwapper, True),
|
|
45
47
|
(ReturnDuplicatorHigh, True),
|
|
48
|
+
(DeadblockRemover, True),
|
|
46
49
|
(SwitchDefaultCaseDuplicator, True),
|
|
47
50
|
(LoweredSwitchSimplifier, False),
|
|
48
51
|
(ReturnDuplicatorLow, True),
|
|
@@ -78,9 +81,7 @@ def get_optimization_passes(arch, platform):
|
|
|
78
81
|
return passes
|
|
79
82
|
|
|
80
83
|
|
|
81
|
-
def get_default_optimization_passes(
|
|
82
|
-
arch: Union[Arch, str], platform: Optional[str], enable_opts=None, disable_opts=None
|
|
83
|
-
):
|
|
84
|
+
def get_default_optimization_passes(arch: Arch | str, platform: str | None, enable_opts=None, disable_opts=None):
|
|
84
85
|
if isinstance(arch, Arch):
|
|
85
86
|
arch = arch.name
|
|
86
87
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import itertools
|
|
2
|
-
from typing import Tuple, List, Optional, Dict
|
|
3
2
|
import logging
|
|
4
3
|
|
|
5
4
|
from ailment import Block
|
|
@@ -79,7 +78,7 @@ class CodeMotionOptimization(OptimizationPass):
|
|
|
79
78
|
|
|
80
79
|
@staticmethod
|
|
81
80
|
def update_graph_with_super_edits(
|
|
82
|
-
original_graph: nx.DiGraph, super_graph: nx.DiGraph, updated_blocks:
|
|
81
|
+
original_graph: nx.DiGraph, super_graph: nx.DiGraph, updated_blocks: dict[Block, Block]
|
|
83
82
|
) -> bool:
|
|
84
83
|
"""
|
|
85
84
|
This function updates an graph when doing block edits on a supergraph version of that same graph.
|
|
@@ -123,7 +122,7 @@ class CodeMotionOptimization(OptimizationPass):
|
|
|
123
122
|
|
|
124
123
|
return False
|
|
125
124
|
|
|
126
|
-
def _move_common_code(self, graph) ->
|
|
125
|
+
def _move_common_code(self, graph) -> tuple[bool, dict[Block, Block] | None]:
|
|
127
126
|
"""
|
|
128
127
|
Does two things at a high level:
|
|
129
128
|
1. rearrange code in blocks to maximize the number of similar statements at the end of the block
|
|
@@ -220,7 +219,7 @@ class CodeMotionOptimization(OptimizationPass):
|
|
|
220
219
|
|
|
221
220
|
def _make_stmts_end_similar(
|
|
222
221
|
self, b0: Block, b1: Block, up=False, down=False
|
|
223
|
-
) ->
|
|
222
|
+
) -> tuple[bool, Block | None, Block | None]:
|
|
224
223
|
"""
|
|
225
224
|
This algorithm attempts to rearrange two blocks to have the longest common sequence of statements
|
|
226
225
|
at either ends of the blocks. It is flawed in that it currently only attempts to do this rearrangement
|
|
@@ -321,7 +320,7 @@ class CodeMotionOptimization(OptimizationPass):
|
|
|
321
320
|
|
|
322
321
|
def _maximize_ends(
|
|
323
322
|
self, b0_stmts, b1_stmts, up=False, down=False
|
|
324
|
-
) ->
|
|
323
|
+
) -> tuple[bool, tuple[list[Statement], list[Statement]]]:
|
|
325
324
|
self._assert_up_or_down(up, down)
|
|
326
325
|
|
|
327
326
|
similar_stmt = b0_stmts[0] if up else b0_stmts[-1]
|
|
@@ -333,7 +332,7 @@ class CodeMotionOptimization(OptimizationPass):
|
|
|
333
332
|
success, new_b1_stmts = self._move_to_end(target_stmt, b1_stmts, up=up, down=down)
|
|
334
333
|
return (success and (b1_stmts != new_b1_stmts)), (b0_stmts, new_b1_stmts)
|
|
335
334
|
|
|
336
|
-
def _move_to_end(self, stmt, stmts, up=False, down=False) ->
|
|
335
|
+
def _move_to_end(self, stmt, stmts, up=False, down=False) -> tuple[bool, list[Statement]]:
|
|
337
336
|
"""
|
|
338
337
|
Attempts to move a stmt to either the top or the bottom of stmts.
|
|
339
338
|
It does this by attempting to swap, 1 by 1, in either direction it is targeting.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# pylint:disable=unused-argument
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from ailment import Block, AILBlockWalker
|
|
@@ -20,7 +20,7 @@ class BlockWalker(AILBlockWalker):
|
|
|
20
20
|
def __init__(self, project: "Project"):
|
|
21
21
|
super().__init__()
|
|
22
22
|
self._project = project
|
|
23
|
-
self._new_block:
|
|
23
|
+
self._new_block: Block | None = None # output
|
|
24
24
|
|
|
25
25
|
def walk(self, block: Block):
|
|
26
26
|
self._new_block = None
|
|
@@ -68,7 +68,7 @@ class BlockWalker(AILBlockWalker):
|
|
|
68
68
|
return new_stmt
|
|
69
69
|
return None
|
|
70
70
|
|
|
71
|
-
def _handle_CallExpr(self, expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block:
|
|
71
|
+
def _handle_CallExpr(self, expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block: Block | None):
|
|
72
72
|
new_target = self._handle_expr(-1, expr.target, stmt_idx, stmt, block)
|
|
73
73
|
|
|
74
74
|
new_args = None
|
|
@@ -260,6 +260,6 @@ class ConstantDereferencesSimplifier(OptimizationPass):
|
|
|
260
260
|
walker = AILGraphWalker(self._graph, handler=self._walk_block, replace_nodes=True)
|
|
261
261
|
walker.walk()
|
|
262
262
|
|
|
263
|
-
def _walk_block(self, block: Block) ->
|
|
263
|
+
def _walk_block(self, block: Block) -> Block | None:
|
|
264
264
|
new_block = self._block_walker.walk(block)
|
|
265
265
|
return new_block
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import networkx
|
|
5
|
+
|
|
6
|
+
import claripy
|
|
7
|
+
|
|
8
|
+
from ailment.statement import Jump
|
|
9
|
+
from ailment.expression import Const
|
|
10
|
+
from angr.utils.graph import to_acyclic_graph
|
|
11
|
+
from angr.analyses.decompiler.condition_processor import ConditionProcessor
|
|
12
|
+
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_l = logging.getLogger(name=__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DeadblockRemover(OptimizationPass):
|
|
19
|
+
"""
|
|
20
|
+
Removes condition-unreachable blocks from the graph.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
ARCHES = None
|
|
24
|
+
PLATFORMS = None
|
|
25
|
+
STAGE = OptimizationPassStage.BEFORE_REGION_IDENTIFICATION
|
|
26
|
+
NAME = "Remove blocks with unsatisfiable conditions"
|
|
27
|
+
DESCRIPTION = __doc__.strip()
|
|
28
|
+
|
|
29
|
+
def __init__(self, func, **kwargs):
|
|
30
|
+
super().__init__(func, **kwargs)
|
|
31
|
+
self.analyze()
|
|
32
|
+
|
|
33
|
+
def _check(self):
|
|
34
|
+
cond_proc = ConditionProcessor(self.project.arch)
|
|
35
|
+
if networkx.is_directed_acyclic_graph(self._graph):
|
|
36
|
+
acyclic_graph = self._graph
|
|
37
|
+
else:
|
|
38
|
+
acyclic_graph = to_acyclic_graph(self._graph)
|
|
39
|
+
cond_proc.recover_reaching_conditions(region=None, graph=acyclic_graph)
|
|
40
|
+
|
|
41
|
+
if not any(claripy.is_false(c) for c in cond_proc.reaching_conditions.values()):
|
|
42
|
+
return False, None
|
|
43
|
+
|
|
44
|
+
cache = {"cond_proc": cond_proc}
|
|
45
|
+
return True, cache
|
|
46
|
+
|
|
47
|
+
def _analyze(self, cache=None):
|
|
48
|
+
cond_proc = cache["cond_proc"]
|
|
49
|
+
to_remove = {
|
|
50
|
+
blk
|
|
51
|
+
for blk in self._graph.nodes()
|
|
52
|
+
if blk.addr != self._func.addr
|
|
53
|
+
and self._graph.in_degree(blk) == 0
|
|
54
|
+
or claripy.is_false(cond_proc.reaching_conditions[blk])
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# fix up predecessors
|
|
58
|
+
for b in to_remove:
|
|
59
|
+
for p in self._graph.predecessors(b):
|
|
60
|
+
if self._graph.out_degree(p) != 2:
|
|
61
|
+
continue
|
|
62
|
+
other_successor = next(s for s in self._graph.successors(p) if s != b)
|
|
63
|
+
p.statements[-1] = Jump(
|
|
64
|
+
None,
|
|
65
|
+
Const(None, None, other_successor.addr, self.project.arch.bits),
|
|
66
|
+
other_successor.idx,
|
|
67
|
+
**p.statements[-1].tags,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
for n in to_remove:
|
|
71
|
+
self._graph.remove_node(n)
|
|
72
|
+
|
|
73
|
+
self.out_graph = self._graph
|
|
@@ -209,9 +209,21 @@ class SimplifierAILEngine(
|
|
|
209
209
|
return operand_expr.operand
|
|
210
210
|
else:
|
|
211
211
|
return Expr.Convert(
|
|
212
|
-
expr.idx,
|
|
212
|
+
expr.idx,
|
|
213
|
+
operand_expr.from_bits,
|
|
214
|
+
expr.to_bits,
|
|
215
|
+
expr.is_signed,
|
|
216
|
+
operand_expr.operand,
|
|
217
|
+
from_type=operand_expr.from_type,
|
|
218
|
+
to_type=expr.to_type,
|
|
219
|
+
rounding_mode=expr.rounding_mode,
|
|
220
|
+
**expr.tags,
|
|
213
221
|
)
|
|
214
|
-
elif
|
|
222
|
+
elif (
|
|
223
|
+
type(operand_expr) is Expr.Const
|
|
224
|
+
and expr.from_type == Expr.Convert.TYPE_INT
|
|
225
|
+
and expr.to_type == Expr.Convert.TYPE_INT
|
|
226
|
+
):
|
|
215
227
|
# do the conversion right away
|
|
216
228
|
value = operand_expr.value
|
|
217
229
|
mask = (2**expr.to_bits) - 1
|
|
@@ -277,5 +289,15 @@ class SimplifierAILEngine(
|
|
|
277
289
|
**operand_expr.tags,
|
|
278
290
|
)
|
|
279
291
|
|
|
280
|
-
converted = Expr.Convert(
|
|
292
|
+
converted = Expr.Convert(
|
|
293
|
+
expr.idx,
|
|
294
|
+
expr.from_bits,
|
|
295
|
+
expr.to_bits,
|
|
296
|
+
expr.is_signed,
|
|
297
|
+
operand_expr,
|
|
298
|
+
from_type=expr.from_type,
|
|
299
|
+
to_type=expr.to_type,
|
|
300
|
+
rounding_mode=expr.rounding_mode,
|
|
301
|
+
**expr.tags,
|
|
302
|
+
)
|
|
281
303
|
return converted
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any, TYPE_CHECKING
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
|
|
4
5
|
from ailment.block import Block as AILBlock
|
|
5
6
|
from ailment.statement import Statement
|
|
@@ -23,7 +24,7 @@ class OuterWalker(SequenceWalker):
|
|
|
23
24
|
|
|
24
25
|
def __init__(self, desc):
|
|
25
26
|
super().__init__()
|
|
26
|
-
self.desc:
|
|
27
|
+
self.desc: dict[OpDescriptor, str] = desc
|
|
27
28
|
|
|
28
29
|
def _handle_Condition(self, node: "ConditionNode", **kwargs):
|
|
29
30
|
for desc, new_op in self.desc.items():
|
|
@@ -56,7 +57,7 @@ class OuterWalker(SequenceWalker):
|
|
|
56
57
|
return super()._handle_ConditionalBreak(node, **kwargs)
|
|
57
58
|
|
|
58
59
|
@staticmethod
|
|
59
|
-
def _swap_expr_op(new_op: str, atom: Expression) ->
|
|
60
|
+
def _swap_expr_op(new_op: str, atom: Expression) -> Expression | None:
|
|
60
61
|
# swap
|
|
61
62
|
new_expr = BinaryOp(
|
|
62
63
|
atom.idx, new_op, (atom.operands[1], atom.operands[0]), atom.signed, bits=atom.bits, **atom.tags
|
|
@@ -76,7 +77,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
76
77
|
self._callback = callback
|
|
77
78
|
|
|
78
79
|
def _handle_expr(
|
|
79
|
-
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt:
|
|
80
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: AILBlock | None
|
|
80
81
|
) -> Any:
|
|
81
82
|
if self._target_expr_predicate(expr):
|
|
82
83
|
new_expr = self._callback(self._block_addr, expr)
|
|
@@ -119,7 +120,7 @@ class ExprOpSwapper(SequenceOptimizationPass):
|
|
|
119
120
|
NAME = "Swap operands of expressions as requested"
|
|
120
121
|
DESCRIPTION = __doc__.strip()
|
|
121
122
|
|
|
122
|
-
def __init__(self, func, binop_operators:
|
|
123
|
+
def __init__(self, func, binop_operators: dict[OpDescriptor, str] | None = None, **kwargs):
|
|
123
124
|
super().__init__(func, **kwargs)
|
|
124
125
|
self._expr_operators = {} if binop_operators is None else binop_operators
|
|
125
126
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# pylint:disable=arguments-renamed,too-many-boolean-expressions
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any
|
|
3
3
|
|
|
4
4
|
import ailment
|
|
5
5
|
from ailment.expression import Op
|
|
@@ -29,7 +29,7 @@ class FlipBooleanWalker(SequenceWalker):
|
|
|
29
29
|
# Type 2:
|
|
30
30
|
# if (cond) { ... } return; --> if (!cond) return; ...
|
|
31
31
|
type1_condition_nodes = [node for node in seq_node.nodes if isinstance(node, ConditionNode) and node.false_node]
|
|
32
|
-
type2_condition_nodes:
|
|
32
|
+
type2_condition_nodes: list[tuple[int, ConditionNode, Any]] = []
|
|
33
33
|
|
|
34
34
|
if len(seq_node.nodes) >= 2:
|
|
35
35
|
idx = len(seq_node.nodes) - 2
|
|
@@ -59,7 +59,7 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
59
59
|
self._callback = callback
|
|
60
60
|
|
|
61
61
|
def _handle_expr(
|
|
62
|
-
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt:
|
|
62
|
+
self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Optional["AILBlock"]
|
|
63
63
|
) -> Any:
|
|
64
64
|
if expr == self._target_expr:
|
|
65
65
|
new_expr = self._callback(self._block_addr, stmt_idx, stmt.ins_addr, expr)
|
|
@@ -101,7 +101,7 @@ class ITEExprConverter(OptimizationPass):
|
|
|
101
101
|
block_walker = ExpressionReplacer(block_addr, expr, self._convert_expr)
|
|
102
102
|
block_walker.walk(block)
|
|
103
103
|
|
|
104
|
-
def _convert_expr(self, block_addr: int, stmt_idx: int, ins_addr: int, atom: Expression) ->
|
|
104
|
+
def _convert_expr(self, block_addr: int, stmt_idx: int, ins_addr: int, atom: Expression) -> Expression | None:
|
|
105
105
|
rda = self.project.analyses[ReachingDefinitionsAnalysis].prep()(subject=self._func, func_graph=self._graph)
|
|
106
106
|
|
|
107
107
|
# find the corresponding definition
|