angr 9.2.102__py3-none-manylinux2014_x86_64.whl → 9.2.103__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/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/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 +239 -236
- {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,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import DefaultDict, TYPE_CHECKING
|
|
2
2
|
from collections import defaultdict, OrderedDict
|
|
3
3
|
import logging
|
|
4
4
|
|
|
@@ -38,12 +38,12 @@ class Case:
|
|
|
38
38
|
def __init__(
|
|
39
39
|
self,
|
|
40
40
|
original_node,
|
|
41
|
-
node_type:
|
|
41
|
+
node_type: str | None,
|
|
42
42
|
variable_hash,
|
|
43
43
|
expr,
|
|
44
|
-
value:
|
|
44
|
+
value: int | str,
|
|
45
45
|
target,
|
|
46
|
-
target_idx:
|
|
46
|
+
target_idx: int | None,
|
|
47
47
|
next_addr,
|
|
48
48
|
):
|
|
49
49
|
self.original_node = original_node
|
|
@@ -104,28 +104,28 @@ class StableVarExprHasher(AILBlockWalkerBase):
|
|
|
104
104
|
self.walk_expression(expr)
|
|
105
105
|
self.hash = hash(tuple(self._hash_lst))
|
|
106
106
|
|
|
107
|
-
def _handle_expr(self, expr_idx: int, expr: Expression, stmt_idx: int, stmt, block:
|
|
107
|
+
def _handle_expr(self, expr_idx: int, expr: Expression, stmt_idx: int, stmt, block: Block | None):
|
|
108
108
|
if hasattr(expr, "variable") and expr.variable is not None:
|
|
109
109
|
self._hash_lst.append(expr.variable)
|
|
110
110
|
else:
|
|
111
111
|
super()._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
|
|
112
112
|
|
|
113
|
-
def _handle_Load(self, expr_idx: int, expr: Load, stmt_idx: int, stmt, block:
|
|
113
|
+
def _handle_Load(self, expr_idx: int, expr: Load, stmt_idx: int, stmt, block: Block | None):
|
|
114
114
|
self._hash_lst.append("Load")
|
|
115
115
|
super()._handle_Load(expr_idx, expr, stmt_idx, stmt, block)
|
|
116
116
|
|
|
117
|
-
def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt, block:
|
|
117
|
+
def _handle_BinaryOp(self, expr_idx: int, expr: BinaryOp, stmt_idx: int, stmt, block: Block | None):
|
|
118
118
|
self._hash_lst.append(expr.op)
|
|
119
119
|
super()._handle_BinaryOp(expr_idx, expr, stmt_idx, stmt, block)
|
|
120
120
|
|
|
121
|
-
def _handle_UnaryOp(self, expr_idx: int, expr: "UnaryOp", stmt_idx: int, stmt, block:
|
|
121
|
+
def _handle_UnaryOp(self, expr_idx: int, expr: "UnaryOp", stmt_idx: int, stmt, block: Block | None):
|
|
122
122
|
self._hash_lst.append(expr.op)
|
|
123
123
|
super()._handle_UnaryOp(expr_idx, expr, stmt_idx, stmt, block)
|
|
124
124
|
|
|
125
|
-
def _handle_Const(self, expr_idx: int, expr: Const, stmt_idx: int, stmt, block:
|
|
125
|
+
def _handle_Const(self, expr_idx: int, expr: Const, stmt_idx: int, stmt, block: Block | None):
|
|
126
126
|
self._hash_lst.append((expr.value, expr.bits))
|
|
127
127
|
|
|
128
|
-
def _handle_Convert(self, expr_idx: int, expr: "Convert", stmt_idx: int, stmt, block:
|
|
128
|
+
def _handle_Convert(self, expr_idx: int, expr: "Convert", stmt_idx: int, stmt, block: Block | None):
|
|
129
129
|
self._hash_lst.append(expr.to_bits)
|
|
130
130
|
super()._handle_Convert(expr_idx, expr, stmt_idx, stmt, block)
|
|
131
131
|
|
|
@@ -174,7 +174,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
174
174
|
original_nodes = original_nodes[1:]
|
|
175
175
|
existing_nodes_by_addr_and_idx = {(nn.addr, nn.idx): nn for nn in graph_copy}
|
|
176
176
|
|
|
177
|
-
case_addrs:
|
|
177
|
+
case_addrs: list[tuple[Block, int | str, int, int | None, int]] = []
|
|
178
178
|
delayed_edges = []
|
|
179
179
|
for idx, case in enumerate(cases):
|
|
180
180
|
if idx == 0 or all(
|
|
@@ -184,7 +184,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
184
184
|
(case.original_node, case.value, case.target, case.target_idx, case.next_addr)
|
|
185
185
|
)
|
|
186
186
|
else:
|
|
187
|
-
statements:
|
|
187
|
+
statements: list = [
|
|
188
188
|
stmt for stmt in case.original_node.statements if isinstance(stmt, (Label, Assignment))
|
|
189
189
|
]
|
|
190
190
|
statements.append(
|
|
@@ -294,7 +294,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
294
294
|
variable_comparisons[node] = ("c",) + r
|
|
295
295
|
continue
|
|
296
296
|
|
|
297
|
-
varhash_to_caselists: DefaultDict[int,
|
|
297
|
+
varhash_to_caselists: DefaultDict[int, list[tuple[list[Case], list]]] = defaultdict(list)
|
|
298
298
|
used_nodes = set()
|
|
299
299
|
|
|
300
300
|
for head in variable_comparisons:
|
|
@@ -516,7 +516,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
516
516
|
@staticmethod
|
|
517
517
|
def _find_switch_variable_comparison_type_a(
|
|
518
518
|
node,
|
|
519
|
-
) ->
|
|
519
|
+
) -> tuple[int, str, Expression, int, int, int | None, int, int | None] | None:
|
|
520
520
|
# the type a is the last statement is a var == constant comparison, but
|
|
521
521
|
# there is more than one non-label statement in the block
|
|
522
522
|
|
|
@@ -561,7 +561,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
561
561
|
@staticmethod
|
|
562
562
|
def _find_switch_variable_comparison_type_b(
|
|
563
563
|
node,
|
|
564
|
-
) ->
|
|
564
|
+
) -> tuple[int, str, Expression, int, int, int | None, int, int | None] | None:
|
|
565
565
|
# the type b is the last statement is a var == constant comparison, and
|
|
566
566
|
# there is only one non-label statement
|
|
567
567
|
|
|
@@ -606,7 +606,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
606
606
|
@staticmethod
|
|
607
607
|
def _find_switch_variable_comparison_type_c(
|
|
608
608
|
node,
|
|
609
|
-
) ->
|
|
609
|
+
) -> tuple[int, str, Expression, int, int, int | None, int, int | None] | None:
|
|
610
610
|
# the type c is where the last statement is a var < or > constant comparison, and
|
|
611
611
|
# there is only one non-label statement
|
|
612
612
|
|
|
@@ -744,7 +744,7 @@ class LoweredSwitchSimplifier(OptimizationPass):
|
|
|
744
744
|
remove_last_statement(node)
|
|
745
745
|
|
|
746
746
|
@staticmethod
|
|
747
|
-
def cases_issubset(cases_0:
|
|
747
|
+
def cases_issubset(cases_0: list[Case], cases_1: list[Case]) -> bool:
|
|
748
748
|
"""
|
|
749
749
|
Test if cases_0 is a subset of cases_1.
|
|
750
750
|
"""
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint:disable=unused-argument
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
from collections.abc import Generator
|
|
3
4
|
from enum import Enum
|
|
4
5
|
|
|
5
6
|
import networkx # pylint:disable=unused-import
|
|
@@ -53,9 +54,7 @@ class BaseOptimizationPass:
|
|
|
53
54
|
ARCHES = [] # strings of supported architectures
|
|
54
55
|
PLATFORMS = [] # strings of supported platforms. Can be one of the following: "win32", "linux"
|
|
55
56
|
STAGE: int = None # Specifies when this optimization pass should be executed
|
|
56
|
-
STRUCTURING:
|
|
57
|
-
None # specifies if this optimization pass is specific to a certain structuring algorithm
|
|
58
|
-
)
|
|
57
|
+
STRUCTURING: str | None = None # specifies if this optimization pass is specific to a certain structuring algorithm
|
|
59
58
|
NAME = "N/A"
|
|
60
59
|
DESCRIPTION = "N/A"
|
|
61
60
|
|
|
@@ -133,23 +132,23 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
133
132
|
):
|
|
134
133
|
super().__init__(func)
|
|
135
134
|
# self._blocks is just a cache
|
|
136
|
-
self._blocks_by_addr:
|
|
137
|
-
self._blocks_by_addr_and_idx:
|
|
138
|
-
self._graph:
|
|
135
|
+
self._blocks_by_addr: dict[int, set[ailment.Block]] = blocks_by_addr
|
|
136
|
+
self._blocks_by_addr_and_idx: dict[tuple[int, int | None], ailment.Block] = blocks_by_addr_and_idx
|
|
137
|
+
self._graph: networkx.DiGraph | None = graph
|
|
139
138
|
self._variable_kb = variable_kb
|
|
140
139
|
self._ri = region_identifier
|
|
141
140
|
self._rd = reaching_definitions
|
|
142
141
|
self._new_block_addrs = set()
|
|
143
142
|
|
|
144
143
|
# output
|
|
145
|
-
self.out_graph:
|
|
144
|
+
self.out_graph: networkx.DiGraph | None = None
|
|
146
145
|
|
|
147
146
|
@property
|
|
148
|
-
def blocks_by_addr(self) ->
|
|
147
|
+
def blocks_by_addr(self) -> dict[int, set[ailment.Block]]:
|
|
149
148
|
return self._blocks_by_addr
|
|
150
149
|
|
|
151
150
|
@property
|
|
152
|
-
def blocks_by_addr_and_idx(self) ->
|
|
151
|
+
def blocks_by_addr_and_idx(self) -> dict[tuple[int, int | None], ailment.Block]:
|
|
153
152
|
return self._blocks_by_addr_and_idx
|
|
154
153
|
|
|
155
154
|
#
|
|
@@ -169,7 +168,7 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
169
168
|
self._new_block_addrs.add(new_addr)
|
|
170
169
|
return new_addr
|
|
171
170
|
|
|
172
|
-
def _get_block(self, addr, idx=None) ->
|
|
171
|
+
def _get_block(self, addr, idx=None) -> ailment.Block | None:
|
|
173
172
|
if not self._blocks_by_addr:
|
|
174
173
|
return None
|
|
175
174
|
else:
|
|
@@ -288,8 +287,8 @@ class StructuringOptimizationPass(OptimizationPass):
|
|
|
288
287
|
self._simplify_ail = simplify_ail
|
|
289
288
|
self._require_gotos = require_gotos
|
|
290
289
|
|
|
291
|
-
self._goto_manager:
|
|
292
|
-
self._prev_graph:
|
|
290
|
+
self._goto_manager: GotoManager | None = None
|
|
291
|
+
self._prev_graph: networkx.DiGraph | None = None
|
|
293
292
|
|
|
294
293
|
def _analyze(self, cache=None) -> bool:
|
|
295
294
|
raise NotImplementedError()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from collections.abc import Iterable
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
import archinfo
|
|
@@ -50,29 +50,33 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
50
50
|
|
|
51
51
|
return bool(info), {"info": info}
|
|
52
52
|
|
|
53
|
+
@staticmethod
|
|
54
|
+
def _modify_statement(
|
|
55
|
+
old_block, stmt_idx_: int, updated_blocks_, stack_offset: int = None
|
|
56
|
+
): # pylint:disable=unused-argument
|
|
57
|
+
if old_block not in updated_blocks_:
|
|
58
|
+
block = old_block.copy()
|
|
59
|
+
updated_blocks_[old_block] = block
|
|
60
|
+
else:
|
|
61
|
+
block = updated_blocks_[old_block]
|
|
62
|
+
block.statements[stmt_idx_] = None
|
|
63
|
+
|
|
53
64
|
def _analyze(self, cache=None):
|
|
54
|
-
def _remove_statement(old_block, stmt_idx_: int, updated_blocks_):
|
|
55
|
-
if old_block not in updated_blocks_:
|
|
56
|
-
block = old_block.copy()
|
|
57
|
-
updated_blocks[old_block] = block
|
|
58
|
-
else:
|
|
59
|
-
block = updated_blocks[old_block]
|
|
60
|
-
block.statements[stmt_idx_] = None
|
|
61
65
|
|
|
62
66
|
if cache is None:
|
|
63
67
|
return
|
|
64
68
|
|
|
65
|
-
info:
|
|
69
|
+
info: dict[int, dict[str, list[tuple[int, CodeLocation]]]] = cache["info"]
|
|
66
70
|
updated_blocks = {}
|
|
67
71
|
|
|
68
72
|
for data in info.values():
|
|
69
73
|
# remove storing statements
|
|
70
|
-
for
|
|
74
|
+
for stack_offset, codeloc in data["stored"]:
|
|
71
75
|
old_block = self._get_block(codeloc.block_addr, idx=codeloc.block_idx)
|
|
72
|
-
|
|
73
|
-
for
|
|
76
|
+
self._modify_statement(old_block, codeloc.stmt_idx, updated_blocks, stack_offset=stack_offset)
|
|
77
|
+
for stack_offset, codeloc in data["restored"]:
|
|
74
78
|
old_block = self._get_block(codeloc.block_addr, idx=codeloc.block_idx)
|
|
75
|
-
|
|
79
|
+
self._modify_statement(old_block, codeloc.stmt_idx, updated_blocks, stack_offset=stack_offset)
|
|
76
80
|
|
|
77
81
|
for old_block, new_block in updated_blocks.items():
|
|
78
82
|
# remove all statements that are None
|
|
@@ -80,7 +84,7 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
80
84
|
# update it
|
|
81
85
|
self._update_block(old_block, new_block)
|
|
82
86
|
|
|
83
|
-
def _find_registers_stored_on_stack(self) ->
|
|
87
|
+
def _find_registers_stored_on_stack(self) -> list[tuple[int, int, CodeLocation]]:
|
|
84
88
|
first_block = self._get_block(self._func.addr)
|
|
85
89
|
if first_block is None:
|
|
86
90
|
return []
|
|
@@ -101,7 +105,7 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
101
105
|
|
|
102
106
|
return results
|
|
103
107
|
|
|
104
|
-
def _find_registers_restored_from_stack(self) ->
|
|
108
|
+
def _find_registers_restored_from_stack(self) -> list[list[tuple[int, int, CodeLocation]]]:
|
|
105
109
|
all_results = []
|
|
106
110
|
for ret_site in self._func.ret_sites + self._func.jumpout_sites:
|
|
107
111
|
for block in self._get_blocks(ret_site.addr):
|
|
@@ -125,10 +129,10 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
125
129
|
|
|
126
130
|
def _intersect_register_info(
|
|
127
131
|
self,
|
|
128
|
-
stored:
|
|
129
|
-
restored: Iterable[
|
|
130
|
-
) ->
|
|
131
|
-
def _collect(info:
|
|
132
|
+
stored: list[tuple[int, int, CodeLocation]],
|
|
133
|
+
restored: Iterable[list[tuple[int, int, CodeLocation]]],
|
|
134
|
+
) -> dict[int, dict[str, list[tuple[int, CodeLocation]]]]:
|
|
135
|
+
def _collect(info: list[tuple[int, int, CodeLocation]], output, keystr: str):
|
|
132
136
|
for reg_offset, stack_offset, codeloc in info:
|
|
133
137
|
if reg_offset not in output:
|
|
134
138
|
output[reg_offset] = {}
|
|
@@ -136,7 +140,7 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
136
140
|
output[reg_offset][keystr] = []
|
|
137
141
|
output[reg_offset][keystr].append((stack_offset, codeloc))
|
|
138
142
|
|
|
139
|
-
result:
|
|
143
|
+
result: dict[int, dict[str, list[tuple[int, CodeLocation]]]] = {}
|
|
140
144
|
_collect(stored, result, "stored")
|
|
141
145
|
for item in restored:
|
|
142
146
|
_collect(item, result, "restored")
|
|
@@ -158,7 +162,7 @@ class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
|
158
162
|
lr_reg_offset = self.project.arch.registers["lr"][0]
|
|
159
163
|
elif self.project.arch.name in {"MIPS32", "MIPS64"}:
|
|
160
164
|
lr_reg_offset = self.project.arch.registers["ra"][0]
|
|
161
|
-
elif self.project.arch.name in {"PPC32", "PPC64"}:
|
|
165
|
+
elif self.project.arch.name in {"PPC32", "PPC64"} or self.project.arch.name.startswith("PowerPC:"):
|
|
162
166
|
lr_reg_offset = self.project.arch.registers["lr"][0]
|
|
163
167
|
else:
|
|
164
168
|
lr_reg_offset = None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
import ailment
|
|
@@ -87,7 +87,7 @@ class RetAddrSaveSimplifier(OptimizationPass):
|
|
|
87
87
|
block_copy.statements.pop(stmt_idx)
|
|
88
88
|
self._update_block(block, block_copy)
|
|
89
89
|
|
|
90
|
-
def _find_retaddr_save_stmt(self) ->
|
|
90
|
+
def _find_retaddr_save_stmt(self) -> tuple[Any, int, ailment.Expr.StackBaseOffset] | None:
|
|
91
91
|
"""
|
|
92
92
|
Find the AIL statement that saves the return address to a stack slot.
|
|
93
93
|
|
|
@@ -126,7 +126,7 @@ class RetAddrSaveSimplifier(OptimizationPass):
|
|
|
126
126
|
# Not found
|
|
127
127
|
return None
|
|
128
128
|
|
|
129
|
-
def _find_retaddr_restore_stmt(self) ->
|
|
129
|
+
def _find_retaddr_restore_stmt(self) -> list[tuple[Any, int, ailment.Expr.StackBaseOffset]] | None:
|
|
130
130
|
"""
|
|
131
131
|
Find the AIL statement that restores the return address from a stack slot.
|
|
132
132
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# pylint:disable=unnecessary-pass
|
|
2
2
|
import logging
|
|
3
|
-
from typing import Tuple, List
|
|
4
3
|
|
|
5
4
|
from ailment import Block
|
|
6
5
|
from ailment.statement import ConditionalJump, Return
|
|
@@ -171,7 +170,7 @@ class ReturnDeduplicator(OptimizationPass):
|
|
|
171
170
|
|
|
172
171
|
return self._get_original_regions(if_ret_candidates)
|
|
173
172
|
|
|
174
|
-
def _get_original_regions(self, if_ret_candidates:
|
|
173
|
+
def _get_original_regions(self, if_ret_candidates: list[tuple[Block, Block, Block]]):
|
|
175
174
|
"""
|
|
176
175
|
Input: [(if_stmt_block, super_true_child, super_false_child), ...]
|
|
177
176
|
Output: [(if_stmt_block, true_child, false_child, super_true_child, super_false_child), ...]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
from itertools import count
|
|
3
3
|
import copy
|
|
4
4
|
import logging
|
|
@@ -32,7 +32,7 @@ class ReturnDuplicatorBase:
|
|
|
32
32
|
node_idx_start: int = 0,
|
|
33
33
|
max_calls_in_regions: int = 2,
|
|
34
34
|
minimize_copies_for_regions: bool = True,
|
|
35
|
-
ri:
|
|
35
|
+
ri: RegionIdentifier | None = None,
|
|
36
36
|
**kwargs,
|
|
37
37
|
):
|
|
38
38
|
self.node_idx = count(start=node_idx_start)
|
|
@@ -41,7 +41,7 @@ class ReturnDuplicatorBase:
|
|
|
41
41
|
|
|
42
42
|
# this should also be set by the optimization passes initer
|
|
43
43
|
self._func = func
|
|
44
|
-
self._ri:
|
|
44
|
+
self._ri: RegionIdentifier | None = ri
|
|
45
45
|
|
|
46
46
|
#
|
|
47
47
|
# must implement these methods
|
|
@@ -88,7 +88,7 @@ class ReturnDuplicatorBase:
|
|
|
88
88
|
|
|
89
89
|
return graph_changed
|
|
90
90
|
|
|
91
|
-
def _find_endnode_regions(self, graph) ->
|
|
91
|
+
def _find_endnode_regions(self, graph) -> dict[Any, tuple[list[tuple[Any, Any]], networkx.DiGraph]]:
|
|
92
92
|
"""
|
|
93
93
|
Find all the regions that contain a node with no successors. These are the "end nodes" of the graph.
|
|
94
94
|
"""
|
|
@@ -97,7 +97,7 @@ class ReturnDuplicatorBase:
|
|
|
97
97
|
# to_update is keyed by the region head.
|
|
98
98
|
# this is because different end nodes may lead to the same region head: consider the case of the typical "fork"
|
|
99
99
|
# region where stack canary is checked in x86-64 binaries.
|
|
100
|
-
end_node_regions:
|
|
100
|
+
end_node_regions: dict[Any, tuple[list[tuple[Any, Any]], networkx.DiGraph]] = {}
|
|
101
101
|
|
|
102
102
|
for end_node in endnodes:
|
|
103
103
|
in_edges = list(graph.in_edges(end_node))
|
|
@@ -175,7 +175,7 @@ class ReturnDuplicatorBase:
|
|
|
175
175
|
graph.remove_edge(pred_node, region_head)
|
|
176
176
|
|
|
177
177
|
def _copy_connected_edge_components(
|
|
178
|
-
self, endnode_regions:
|
|
178
|
+
self, endnode_regions: dict[Any, tuple[list[tuple[Any, Any]], networkx.DiGraph]], graph: networkx.DiGraph
|
|
179
179
|
):
|
|
180
180
|
updated_regions = endnode_regions.copy()
|
|
181
181
|
all_region_block_addrs = list(self._find_block_sets_in_all_regions(self._ri.region).values())
|
|
@@ -312,7 +312,7 @@ class ReturnDuplicatorBase:
|
|
|
312
312
|
return valid_assignment
|
|
313
313
|
|
|
314
314
|
@staticmethod
|
|
315
|
-
def _single_entry_region(graph, end_node) ->
|
|
315
|
+
def _single_entry_region(graph, end_node) -> tuple[networkx.DiGraph, Any]:
|
|
316
316
|
"""
|
|
317
317
|
Back track on the graph from `end_node` and find the longest chain of nodes where each node has only one
|
|
318
318
|
predecessor and one successor (the second-to-last node may have two successors to account for the typical
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .register_save_area_simplifier import RegisterSaveAreaSimplifier
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
_l = logging.getLogger(name=__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SpilledRegisterFinder(RegisterSaveAreaSimplifier):
|
|
10
|
+
"""
|
|
11
|
+
Finds spilled registers and tags them with pseudoregisters based on their stack offset.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def _modify_statement(old_block, stmt_idx_: int, updated_blocks_, stack_offset: int = None):
|
|
16
|
+
old_stmt = old_block.statements[stmt_idx_]
|
|
17
|
+
pseudoreg = 0x1000000 - stack_offset
|
|
18
|
+
old_stmt.tags["pseudoreg"] = pseudoreg
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from typing import Set, Dict
|
|
2
1
|
from collections import defaultdict
|
|
3
2
|
import logging
|
|
4
3
|
|
|
@@ -74,7 +73,7 @@ class StackCanarySimplifier(OptimizationPass):
|
|
|
74
73
|
# Before node duplication, each pair of canary-check-success and canary-check-failure nodes have a common
|
|
75
74
|
# predecessor.
|
|
76
75
|
# map endpoint addrs to their common predecessors
|
|
77
|
-
pred_addr_to_endpoint_addrs:
|
|
76
|
+
pred_addr_to_endpoint_addrs: dict[int, set[int]] = defaultdict(set)
|
|
78
77
|
for node_addr in all_endpoint_addrs:
|
|
79
78
|
preds = self._func.graph.predecessors(self._func.get_node(node_addr))
|
|
80
79
|
for pred in preds:
|
|
@@ -183,7 +182,7 @@ class StackCanarySimplifier(OptimizationPass):
|
|
|
183
182
|
|
|
184
183
|
while True:
|
|
185
184
|
traversed.add(block_addr)
|
|
186
|
-
first_block = self.
|
|
185
|
+
first_block = next(self._get_blocks(block_addr))
|
|
187
186
|
if first_block is None:
|
|
188
187
|
break
|
|
189
188
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=too-many-boolean-expressions
|
|
2
|
-
from typing import Set, Dict
|
|
3
2
|
from collections import defaultdict
|
|
4
3
|
import logging
|
|
5
4
|
|
|
@@ -90,7 +89,7 @@ class WinStackCanarySimplifier(OptimizationPass):
|
|
|
90
89
|
# Before node duplication, each pair of canary-check-success and canary-check-failure nodes have a common
|
|
91
90
|
# predecessor.
|
|
92
91
|
# map endpoint addrs to their common predecessors
|
|
93
|
-
pred_addr_to_endpoint_addrs:
|
|
92
|
+
pred_addr_to_endpoint_addrs: dict[int, set[int]] = defaultdict(set)
|
|
94
93
|
for node_addr in all_endpoint_addrs:
|
|
95
94
|
preds = self._func.graph.predecessors(self._func.get_node(node_addr))
|
|
96
95
|
for pred in preds:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
import ailment
|
|
@@ -60,7 +60,7 @@ class X86GccGetPcSimplifier(OptimizationPass):
|
|
|
60
60
|
block.statements = block.statements[: stmt_idx - 1] + block.statements[stmt_idx:]
|
|
61
61
|
self._update_block(old_block, block)
|
|
62
62
|
|
|
63
|
-
def _find_getpc_calls(self) ->
|
|
63
|
+
def _find_getpc_calls(self) -> list[tuple[Any, int, str, int]]:
|
|
64
64
|
"""
|
|
65
65
|
Find all blocks that are calling __x86.get_pc_thunk functions.
|
|
66
66
|
|
|
@@ -43,12 +43,13 @@ from .rol_ror import RolRorRewriter
|
|
|
43
43
|
from .inlined_strcpy import InlinedStrcpy
|
|
44
44
|
from .inlined_strcpy_consolidation import InlinedStrcpyConsolidation
|
|
45
45
|
from .inlined_wstrcpy import InlinedWstrcpy
|
|
46
|
+
from .cmpord_rewriter import CmpORDRewriter
|
|
46
47
|
|
|
47
48
|
from .base import PeepholeOptimizationExprBase, PeepholeOptimizationStmtBase, PeepholeOptimizationMultiStmtBase
|
|
48
49
|
|
|
49
|
-
MULTI_STMT_OPTS:
|
|
50
|
-
STMT_OPTS:
|
|
51
|
-
EXPR_OPTS:
|
|
50
|
+
MULTI_STMT_OPTS: list[type[PeepholeOptimizationMultiStmtBase]] = []
|
|
51
|
+
STMT_OPTS: list[type[PeepholeOptimizationStmtBase]] = []
|
|
52
|
+
EXPR_OPTS: list[type[PeepholeOptimizationExprBase]] = []
|
|
52
53
|
|
|
53
54
|
_g = globals().copy()
|
|
54
55
|
for v in _g.values():
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
2
|
-
|
|
3
1
|
from ailment.expression import BinaryOp, UnaryOp, Expression
|
|
4
2
|
from ailment.statement import Statement, Assignment
|
|
5
3
|
from ailment import Block
|
|
@@ -17,15 +15,15 @@ class PeepholeOptimizationStmtBase:
|
|
|
17
15
|
"kb",
|
|
18
16
|
"func_addr",
|
|
19
17
|
)
|
|
20
|
-
project:
|
|
21
|
-
kb:
|
|
22
|
-
func_addr:
|
|
18
|
+
project: Project | None
|
|
19
|
+
kb: KnowledgeBase | None
|
|
20
|
+
func_addr: int | None
|
|
23
21
|
|
|
24
22
|
NAME = "Peephole Optimization - Statement"
|
|
25
23
|
DESCRIPTION = "Peephole Optimization - Statement"
|
|
26
24
|
stmt_classes = None
|
|
27
25
|
|
|
28
|
-
def __init__(self, project:
|
|
26
|
+
def __init__(self, project: Project | None, kb: KnowledgeBase | None, func_addr: int | None = None):
|
|
29
27
|
self.project = project
|
|
30
28
|
self.kb = kb
|
|
31
29
|
self.func_addr = func_addr
|
|
@@ -44,20 +42,20 @@ class PeepholeOptimizationMultiStmtBase:
|
|
|
44
42
|
"kb",
|
|
45
43
|
"func_addr",
|
|
46
44
|
)
|
|
47
|
-
project:
|
|
48
|
-
kb:
|
|
49
|
-
func_addr:
|
|
45
|
+
project: Project | None
|
|
46
|
+
kb: KnowledgeBase | None
|
|
47
|
+
func_addr: int | None
|
|
50
48
|
|
|
51
49
|
NAME = "Peephole Optimization - Multi-statement"
|
|
52
50
|
DESCRIPTION = "Peephole Optimization - Multi-statement"
|
|
53
51
|
stmt_classes = None
|
|
54
52
|
|
|
55
|
-
def __init__(self, project:
|
|
53
|
+
def __init__(self, project: Project | None, kb: KnowledgeBase | None, func_addr: int | None = None):
|
|
56
54
|
self.project = project
|
|
57
55
|
self.kb = kb
|
|
58
56
|
self.func_addr = func_addr
|
|
59
57
|
|
|
60
|
-
def optimize(self, stmts:
|
|
58
|
+
def optimize(self, stmts: list[Statement], stmt_idx: int | None = None, block=None, **kwargs):
|
|
61
59
|
raise NotImplementedError("_optimize() is not implemented.")
|
|
62
60
|
|
|
63
61
|
|
|
@@ -71,15 +69,15 @@ class PeepholeOptimizationExprBase:
|
|
|
71
69
|
"kb",
|
|
72
70
|
"func_addr",
|
|
73
71
|
)
|
|
74
|
-
project:
|
|
75
|
-
kb:
|
|
76
|
-
func_addr:
|
|
72
|
+
project: Project | None
|
|
73
|
+
kb: KnowledgeBase | None
|
|
74
|
+
func_addr: int | None
|
|
77
75
|
|
|
78
76
|
NAME = "Peephole Optimization - Expression"
|
|
79
77
|
DESCRIPTION = "Peephole Optimization - Expression"
|
|
80
78
|
expr_classes = None
|
|
81
79
|
|
|
82
|
-
def __init__(self, project:
|
|
80
|
+
def __init__(self, project: Project | None, kb: KnowledgeBase | None, func_addr: int | None = None):
|
|
83
81
|
self.project = project
|
|
84
82
|
self.kb = kb
|
|
85
83
|
self.func_addr = func_addr
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Tuple, Optional
|
|
2
|
-
|
|
3
1
|
from ailment.expression import BinaryOp, Const, Expression, Convert
|
|
4
2
|
from ailment.statement import Call
|
|
5
3
|
|
|
@@ -101,7 +99,7 @@ class Bswap(PeepholeOptimizationExprBase):
|
|
|
101
99
|
|
|
102
100
|
return None
|
|
103
101
|
|
|
104
|
-
def _match_inner(self, or_first: BinaryOp, or_second: BinaryOp) ->
|
|
102
|
+
def _match_inner(self, or_first: BinaryOp, or_second: BinaryOp) -> tuple[bool, Expression | None]:
|
|
105
103
|
if isinstance(or_first.operands[1], Const) and or_first.operands[1].value == 0xFF00FF00:
|
|
106
104
|
if isinstance(or_second.operands[1], Const) and or_second.operands[1].value == 0x00FF00FF:
|
|
107
105
|
inner_first = or_first.operands[0]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from ailment.statement import ConditionalJump
|
|
2
|
+
from ailment.expression import BinaryOp, Const
|
|
3
|
+
|
|
4
|
+
from .base import PeepholeOptimizationStmtBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CmpORDRewriter(PeepholeOptimizationStmtBase):
|
|
8
|
+
"""
|
|
9
|
+
Rewrites CmpORD expressions (PowerPC and VEX-specific) into common comparison operations.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__slots__ = ()
|
|
13
|
+
|
|
14
|
+
NAME = "CmpORD rewriter"
|
|
15
|
+
stmt_classes = (ConditionalJump,)
|
|
16
|
+
|
|
17
|
+
def optimize(self, stmt: ConditionalJump, stmt_idx: int = None, block=None, **kwargs):
|
|
18
|
+
# example:
|
|
19
|
+
# 05 | 0x4011d4 | if ((((gpr9<4> CmpORD 0x0<32>) & 0x2<32>) != 0x0<32>)) { Goto ... } else { Goto ... }
|
|
20
|
+
# or
|
|
21
|
+
# 02 | 0x401260 | if (((((gpr3<4> CmpORD 0x0<32>) & 0x2<32>) ^ 0x2<32>) != 0x0<32>)) { Goto ... } else
|
|
22
|
+
# { Goto ... }
|
|
23
|
+
|
|
24
|
+
if not isinstance(stmt.condition, BinaryOp) or stmt.condition.op not in {"CmpNE", "CmpEQ"}:
|
|
25
|
+
return None
|
|
26
|
+
cmp_rhs = stmt.condition.operands[1]
|
|
27
|
+
if not isinstance(cmp_rhs, Const) or cmp_rhs.value != 0:
|
|
28
|
+
return None
|
|
29
|
+
negated = stmt.condition.op == "CmpEQ"
|
|
30
|
+
|
|
31
|
+
cmp_lhs = stmt.condition.operands[0]
|
|
32
|
+
xor_value = None
|
|
33
|
+
if isinstance(cmp_lhs, BinaryOp) and cmp_lhs.op == "Xor" and isinstance(cmp_lhs.operands[1], Const):
|
|
34
|
+
negated = not negated
|
|
35
|
+
xor_value = cmp_lhs.operands[1].value
|
|
36
|
+
# unpack
|
|
37
|
+
cmp_lhs = cmp_lhs.operands[0]
|
|
38
|
+
|
|
39
|
+
if not isinstance(cmp_lhs, BinaryOp) or cmp_lhs.op != "And":
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
if not isinstance(cmp_lhs.operands[1], Const) or cmp_lhs.operands[1].value not in {2, 4, 8}:
|
|
43
|
+
return None
|
|
44
|
+
if xor_value is not None and cmp_lhs.operands[1].value != xor_value:
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
real_cmp = cmp_lhs.operands[0]
|
|
48
|
+
if not isinstance(real_cmp, BinaryOp) or real_cmp.op != "CmpORD":
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
# determine the real comparison operator
|
|
52
|
+
match cmp_lhs.operands[1].value:
|
|
53
|
+
case 2:
|
|
54
|
+
cmp_op = "CmpEQ" if not negated else "CmpNE"
|
|
55
|
+
case 4:
|
|
56
|
+
cmp_op = "CmpGE" if not negated else "CmpLT"
|
|
57
|
+
case _: # case 8
|
|
58
|
+
cmp_op = "CmpLT" if not negated else "CmpGE"
|
|
59
|
+
|
|
60
|
+
# generate the new comparison
|
|
61
|
+
new_cond = BinaryOp(stmt.condition.idx, cmp_op, real_cmp.operands[::], real_cmp.signed, **real_cmp.tags)
|
|
62
|
+
new_stmt = ConditionalJump(
|
|
63
|
+
stmt.idx,
|
|
64
|
+
new_cond,
|
|
65
|
+
stmt.true_target,
|
|
66
|
+
stmt.false_target,
|
|
67
|
+
stmt.true_target_idx,
|
|
68
|
+
stmt.false_target_idx,
|
|
69
|
+
**stmt.tags,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return new_stmt
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# pylint:disable=too-many-boolean-expressions
|
|
2
|
-
from typing import Union
|
|
3
2
|
|
|
4
3
|
from ailment.expression import Convert, BinaryOp, Const
|
|
5
4
|
|
|
@@ -16,7 +15,7 @@ class ConstMullAShift(PeepholeOptimizationExprBase):
|
|
|
16
15
|
NAME = "Conv(64->32, (N * a) >> M) => a / N1"
|
|
17
16
|
expr_classes = (Convert, BinaryOp)
|
|
18
17
|
|
|
19
|
-
def optimize(self, expr:
|
|
18
|
+
def optimize(self, expr: Convert | BinaryOp, **kwargs):
|
|
20
19
|
r = None
|
|
21
20
|
|
|
22
21
|
if isinstance(expr, Convert):
|