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,6 @@
|
|
|
1
1
|
# pylint:disable=line-too-long,import-outside-toplevel,import-error,multiple-statements,too-many-boolean-expressions
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any, DefaultDict, Optional, TYPE_CHECKING
|
|
3
|
+
from collections import OrderedDict as ODict
|
|
3
4
|
from collections import defaultdict, OrderedDict
|
|
4
5
|
from enum import Enum
|
|
5
6
|
import logging
|
|
@@ -80,7 +81,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
80
81
|
parent_map=None,
|
|
81
82
|
condition_processor=None,
|
|
82
83
|
func: Optional["Function"] = None,
|
|
83
|
-
case_entry_to_switch_head:
|
|
84
|
+
case_entry_to_switch_head: dict[int, int] | None = None,
|
|
84
85
|
parent_region=None,
|
|
85
86
|
improve_structurer=True,
|
|
86
87
|
use_multistmtexprs: MultiStmtExprMode = MultiStmtExprMode.MAX_ONE_CALL,
|
|
@@ -101,14 +102,14 @@ class PhoenixStructurer(StructurerBase):
|
|
|
101
102
|
# structuring cycles.
|
|
102
103
|
# the set is populated during the analysis. _last_resort_refinement() will ensure not to remove any edges
|
|
103
104
|
# who fall into these sets.
|
|
104
|
-
self.whitelist_edges:
|
|
105
|
+
self.whitelist_edges: set[tuple[int, int]] = set()
|
|
105
106
|
# also whitelist certain nodes that are definitely header for switch-case constructs. they should not be merged
|
|
106
107
|
# into another node before we successfully structure the entire switch-case.
|
|
107
|
-
self.switch_case_known_heads:
|
|
108
|
+
self.switch_case_known_heads: set[Block] = set()
|
|
108
109
|
|
|
109
110
|
# whitelist certain nodes that should be treated as a tail node for do-whiles. these nodes should not be
|
|
110
111
|
# absorbed into other SequenceNodes
|
|
111
|
-
self.dowhile_known_tail_nodes:
|
|
112
|
+
self.dowhile_known_tail_nodes: set = set()
|
|
112
113
|
|
|
113
114
|
self._phoenix_improved = self._improve_structurer
|
|
114
115
|
self._edge_virtualization_hints = []
|
|
@@ -266,7 +267,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
266
267
|
self._rewrite_jumps_to_continues(loop_node.sequence_node)
|
|
267
268
|
return matched
|
|
268
269
|
|
|
269
|
-
def _match_cyclic_while(self, node, head, graph, full_graph) ->
|
|
270
|
+
def _match_cyclic_while(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None, BaseNode | None]:
|
|
270
271
|
succs = list(full_graph.successors(node))
|
|
271
272
|
if len(succs) == 2:
|
|
272
273
|
left, right = succs
|
|
@@ -406,7 +407,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
406
407
|
|
|
407
408
|
def _match_cyclic_while_with_single_successor(
|
|
408
409
|
self, node, head, graph, full_graph
|
|
409
|
-
) ->
|
|
410
|
+
) -> tuple[bool, LoopNode | None, BaseNode | None]:
|
|
410
411
|
if self._region.successors:
|
|
411
412
|
return False, None, None
|
|
412
413
|
if node is not head:
|
|
@@ -474,9 +475,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
474
475
|
|
|
475
476
|
return True, loop_node, successor_node
|
|
476
477
|
|
|
477
|
-
def _match_cyclic_dowhile(
|
|
478
|
-
self, node, head, graph, full_graph
|
|
479
|
-
) -> Tuple[bool, Optional[LoopNode], Optional[BaseNode]]:
|
|
478
|
+
def _match_cyclic_dowhile(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None, BaseNode | None]:
|
|
480
479
|
preds = list(full_graph.predecessors(node))
|
|
481
480
|
succs = list(full_graph.successors(node))
|
|
482
481
|
if ((node is head and len(preds) >= 1) or len(preds) >= 2) and len(succs) == 1:
|
|
@@ -543,7 +542,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
543
542
|
return True, loop_node, succ
|
|
544
543
|
return False, None, None
|
|
545
544
|
|
|
546
|
-
def _match_cyclic_natural_loop(self, node, head, graph, full_graph) ->
|
|
545
|
+
def _match_cyclic_natural_loop(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None]:
|
|
547
546
|
if not (node is head or graph.in_degree[node] == 2):
|
|
548
547
|
return False, None
|
|
549
548
|
|
|
@@ -609,8 +608,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
609
608
|
is_while, result_while = self._refine_cyclic_is_while_loop(graph, fullgraph, loop_head, head_succs)
|
|
610
609
|
is_dowhile, result_dowhile = self._refine_cyclic_is_dowhile_loop(graph, fullgraph, loop_head, head_succs)
|
|
611
610
|
|
|
612
|
-
continue_edges:
|
|
613
|
-
outgoing_edges:
|
|
611
|
+
continue_edges: list[tuple[BaseNode, BaseNode]] = []
|
|
612
|
+
outgoing_edges: list = []
|
|
614
613
|
|
|
615
614
|
if is_while and is_dowhile:
|
|
616
615
|
# gotta pick one!
|
|
@@ -872,7 +871,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
872
871
|
|
|
873
872
|
def _refine_cyclic_is_while_loop(
|
|
874
873
|
self, graph, fullgraph, loop_head, head_succs
|
|
875
|
-
) ->
|
|
874
|
+
) -> tuple[bool, tuple[list, list, BaseNode, BaseNode] | None]:
|
|
876
875
|
if len(head_succs) == 2 and any(head_succ not in graph for head_succ in head_succs):
|
|
877
876
|
# make sure the head_pred is not already structured
|
|
878
877
|
_, _, head_block_0 = self._find_node_going_to_dst(loop_head, head_succs[0])
|
|
@@ -880,7 +879,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
880
879
|
if head_block_0 is head_block_1 and head_block_0 is not None:
|
|
881
880
|
# there is an out-going edge from the loop head
|
|
882
881
|
# virtualize all other edges
|
|
883
|
-
continue_edges:
|
|
882
|
+
continue_edges: list[tuple[BaseNode, BaseNode]] = []
|
|
884
883
|
outgoing_edges = []
|
|
885
884
|
successor = next(iter(head_succ for head_succ in head_succs if head_succ not in graph))
|
|
886
885
|
for node in networkx.descendants(graph, loop_head):
|
|
@@ -897,7 +896,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
897
896
|
|
|
898
897
|
def _refine_cyclic_is_dowhile_loop( # pylint:disable=unused-argument
|
|
899
898
|
self, graph, fullgraph, loop_head, head_succs
|
|
900
|
-
) ->
|
|
899
|
+
) -> tuple[bool, tuple[list, list, BaseNode, BaseNode] | None]:
|
|
901
900
|
# check if there is an out-going edge from the loop tail
|
|
902
901
|
head_preds = list(fullgraph.predecessors(loop_head))
|
|
903
902
|
if len(head_preds) == 1:
|
|
@@ -908,7 +907,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
908
907
|
_, _, src_block_0 = self._find_node_going_to_dst(head_pred, head_pred_succs[0])
|
|
909
908
|
_, _, src_block_1 = self._find_node_going_to_dst(head_pred, head_pred_succs[1])
|
|
910
909
|
if src_block_0 is src_block_1 and src_block_0 is not None:
|
|
911
|
-
continue_edges:
|
|
910
|
+
continue_edges: list[tuple[BaseNode, BaseNode]] = []
|
|
912
911
|
outgoing_edges = []
|
|
913
912
|
# there is an out-going edge from the loop tail
|
|
914
913
|
# virtualize all other edges
|
|
@@ -1047,7 +1046,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1047
1046
|
|
|
1048
1047
|
# make a fake jumptable
|
|
1049
1048
|
node_default_addr = None
|
|
1050
|
-
case_entries:
|
|
1049
|
+
case_entries: dict[int, tuple[int, int | None]] = {}
|
|
1051
1050
|
for _, case_value, case_target_addr, case_target_idx, _ in last_stmt.case_addrs:
|
|
1052
1051
|
if isinstance(case_value, str):
|
|
1053
1052
|
if case_value == "default":
|
|
@@ -1264,7 +1263,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1264
1263
|
return True
|
|
1265
1264
|
|
|
1266
1265
|
def _match_acyclic_incomplete_switch_cases(
|
|
1267
|
-
self, node, graph: networkx.DiGraph, full_graph: networkx.DiGraph, jump_tables:
|
|
1266
|
+
self, node, graph: networkx.DiGraph, full_graph: networkx.DiGraph, jump_tables: dict
|
|
1268
1267
|
) -> bool:
|
|
1269
1268
|
# sanity checks
|
|
1270
1269
|
if node.addr not in jump_tables:
|
|
@@ -1300,14 +1299,14 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1300
1299
|
|
|
1301
1300
|
def _switch_build_cases(
|
|
1302
1301
|
self,
|
|
1303
|
-
case_and_entryaddrs:
|
|
1302
|
+
case_and_entryaddrs: dict[int, int | tuple[int, int | None]],
|
|
1304
1303
|
head_node,
|
|
1305
1304
|
node_a: BaseNode,
|
|
1306
1305
|
node_b_addr,
|
|
1307
1306
|
graph,
|
|
1308
1307
|
full_graph,
|
|
1309
|
-
) ->
|
|
1310
|
-
cases: ODict[
|
|
1308
|
+
) -> tuple[ODict, Any, set[Any]]:
|
|
1309
|
+
cases: ODict[int | tuple[int], SequenceNode] = OrderedDict()
|
|
1311
1310
|
to_remove = set()
|
|
1312
1311
|
|
|
1313
1312
|
# it is possible that the default node gets duplicated by other analyses and creates a default node (addr.a)
|
|
@@ -1315,11 +1314,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1315
1314
|
# successor to node_a
|
|
1316
1315
|
default_node_candidates = [nn for nn in graph.nodes if nn.addr == node_b_addr]
|
|
1317
1316
|
if len(default_node_candidates) == 0:
|
|
1318
|
-
node_default:
|
|
1317
|
+
node_default: BaseNode | None = None
|
|
1319
1318
|
elif len(default_node_candidates) == 1:
|
|
1320
|
-
node_default:
|
|
1319
|
+
node_default: BaseNode | None = default_node_candidates[0]
|
|
1321
1320
|
else:
|
|
1322
|
-
node_default:
|
|
1321
|
+
node_default: BaseNode | None = next(
|
|
1323
1322
|
iter(nn for nn in default_node_candidates if graph.has_edge(head_node, nn)), None
|
|
1324
1323
|
)
|
|
1325
1324
|
|
|
@@ -1331,8 +1330,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1331
1330
|
node_default = new_node
|
|
1332
1331
|
|
|
1333
1332
|
# entry_addrs_set = set(jumptable_entries)
|
|
1334
|
-
converted_nodes:
|
|
1335
|
-
entry_addr_to_ids: DefaultDict[
|
|
1333
|
+
converted_nodes: dict[tuple[int, int | None], Any] = {}
|
|
1334
|
+
entry_addr_to_ids: DefaultDict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1336
1335
|
|
|
1337
1336
|
# the default node might get duplicated (e.g., by EagerReturns). we detect if a duplicate of the default node
|
|
1338
1337
|
# (node b) is a successor node of node a. we only skip those entries going to the default node if no duplicate
|
|
@@ -1420,7 +1419,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1420
1419
|
node_default_addr: int,
|
|
1421
1420
|
node_default,
|
|
1422
1421
|
addr,
|
|
1423
|
-
to_remove:
|
|
1422
|
+
to_remove: set,
|
|
1424
1423
|
graph: networkx.DiGraph,
|
|
1425
1424
|
full_graph: networkx.DiGraph,
|
|
1426
1425
|
node_a=None,
|
|
@@ -1952,7 +1951,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1952
1951
|
|
|
1953
1952
|
def _match_acyclic_short_circuit_conditions_type_a( # pylint:disable=unused-argument
|
|
1954
1953
|
self, graph, full_graph, start_node
|
|
1955
|
-
) ->
|
|
1954
|
+
) -> tuple | None:
|
|
1956
1955
|
# if (a) goto right
|
|
1957
1956
|
# else if (b) goto right
|
|
1958
1957
|
# else goto other_succ
|
|
@@ -1990,7 +1989,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1990
1989
|
|
|
1991
1990
|
def _match_acyclic_short_circuit_conditions_type_b( # pylint:disable=unused-argument
|
|
1992
1991
|
self, graph, full_graph, start_node
|
|
1993
|
-
) ->
|
|
1992
|
+
) -> tuple | None:
|
|
1994
1993
|
# if (a) goto left
|
|
1995
1994
|
# right:
|
|
1996
1995
|
# else if (b) goto left
|
|
@@ -2032,7 +2031,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2032
2031
|
|
|
2033
2032
|
def _match_acyclic_short_circuit_conditions_type_c( # pylint:disable=unused-argument
|
|
2034
2033
|
self, graph, full_graph, start_node
|
|
2035
|
-
) ->
|
|
2034
|
+
) -> tuple | None:
|
|
2036
2035
|
# if (a) goto successor
|
|
2037
2036
|
# else if (b) goto successor
|
|
2038
2037
|
# right:
|
|
@@ -2070,7 +2069,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2070
2069
|
|
|
2071
2070
|
def _match_acyclic_short_circuit_conditions_type_d( # pylint:disable=unused-argument
|
|
2072
2071
|
self, graph, full_graph, start_node
|
|
2073
|
-
) ->
|
|
2072
|
+
) -> tuple | None:
|
|
2074
2073
|
# if (a) goto else_node
|
|
2075
2074
|
# left:
|
|
2076
2075
|
# else if (b) goto else_node
|
|
@@ -2107,7 +2106,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2107
2106
|
return left, edge_cond_left, right, edge_cond_left_right, else_node
|
|
2108
2107
|
return None
|
|
2109
2108
|
|
|
2110
|
-
def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph:
|
|
2109
|
+
def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph: networkx.DiGraph | None) -> bool:
|
|
2111
2110
|
if self._phoenix_improved:
|
|
2112
2111
|
while self._edge_virtualization_hints:
|
|
2113
2112
|
src, dst = self._edge_virtualization_hints.pop(0)
|
|
@@ -2228,7 +2227,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2228
2227
|
if remove_src_last_stmt:
|
|
2229
2228
|
remove_last_statement(src)
|
|
2230
2229
|
|
|
2231
|
-
def _should_use_multistmtexprs(self, node:
|
|
2230
|
+
def _should_use_multistmtexprs(self, node: Block | BaseNode) -> bool:
|
|
2232
2231
|
if self._use_multistmtexprs == MultiStmtExprMode.NEVER:
|
|
2233
2232
|
return False
|
|
2234
2233
|
if self._use_multistmtexprs == MultiStmtExprMode.ALWAYS:
|
|
@@ -2244,10 +2243,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2244
2243
|
@staticmethod
|
|
2245
2244
|
def _find_node_going_to_dst(
|
|
2246
2245
|
node: SequenceNode,
|
|
2247
|
-
dst:
|
|
2246
|
+
dst: Block | BaseNode,
|
|
2248
2247
|
last=True,
|
|
2249
2248
|
condjump_only=False,
|
|
2250
|
-
) ->
|
|
2249
|
+
) -> tuple[int | None, BaseNode | None, Block | None]:
|
|
2251
2250
|
"""
|
|
2252
2251
|
|
|
2253
2252
|
:param node:
|
|
@@ -2335,7 +2334,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2335
2334
|
update_seqnode_in_place=False,
|
|
2336
2335
|
force_forward_scan=True,
|
|
2337
2336
|
)
|
|
2338
|
-
walker.parent_and_block:
|
|
2337
|
+
walker.parent_and_block: list[tuple[int, Any, Block | MultiNode]] = []
|
|
2339
2338
|
walker.block_id = -1
|
|
2340
2339
|
walker.walk(node)
|
|
2341
2340
|
if not walker.parent_and_block:
|
|
@@ -2385,7 +2384,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2385
2384
|
graph.add_edge(case_node, succs[0])
|
|
2386
2385
|
|
|
2387
2386
|
@staticmethod
|
|
2388
|
-
def _count_statements(node:
|
|
2387
|
+
def _count_statements(node: BaseNode | Block) -> int:
|
|
2389
2388
|
if isinstance(node, Block):
|
|
2390
2389
|
return sum(1 for stmt in node.statements if not isinstance(stmt, Label))
|
|
2391
2390
|
elif isinstance(node, MultiNode):
|
|
@@ -2395,19 +2394,19 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2395
2394
|
return 1
|
|
2396
2395
|
|
|
2397
2396
|
@staticmethod
|
|
2398
|
-
def _is_single_statement_block(node:
|
|
2397
|
+
def _is_single_statement_block(node: BaseNode | Block) -> bool:
|
|
2399
2398
|
if isinstance(node, (Block, MultiNode, SequenceNode)):
|
|
2400
2399
|
return PhoenixStructurer._count_statements(node) == 1
|
|
2401
2400
|
return False
|
|
2402
2401
|
|
|
2403
2402
|
@staticmethod
|
|
2404
|
-
def _is_sequential_statement_block(node:
|
|
2403
|
+
def _is_sequential_statement_block(node: BaseNode | Block) -> bool:
|
|
2405
2404
|
"""
|
|
2406
2405
|
Examine if the node can be converted into a MultiStatementExpression object. The conversion fails if there are
|
|
2407
2406
|
any conditional statements or goto statements before the very last statement of the node.
|
|
2408
2407
|
"""
|
|
2409
2408
|
|
|
2410
|
-
def _is_sequential_statement_list(stmts:
|
|
2409
|
+
def _is_sequential_statement_list(stmts: list[Statement]) -> bool:
|
|
2411
2410
|
if not stmts:
|
|
2412
2411
|
return True
|
|
2413
2412
|
for stmt in stmts[:-1]:
|
|
@@ -2421,7 +2420,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2421
2420
|
return False
|
|
2422
2421
|
return True
|
|
2423
2422
|
|
|
2424
|
-
def _to_statement_list(node:
|
|
2423
|
+
def _to_statement_list(node: Block | MultiNode | SequenceNode) -> list[Statement]:
|
|
2425
2424
|
if isinstance(node, Block):
|
|
2426
2425
|
return node.statements
|
|
2427
2426
|
if isinstance(node, MultiNode):
|
|
@@ -2444,7 +2443,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2444
2443
|
return _is_sequential_statement_list(stmt_list)
|
|
2445
2444
|
|
|
2446
2445
|
@staticmethod
|
|
2447
|
-
def _build_multistatementexpr_statements(block) ->
|
|
2446
|
+
def _build_multistatementexpr_statements(block) -> list[Statement] | None:
|
|
2448
2447
|
stmts = []
|
|
2449
2448
|
if isinstance(block, (SequenceNode, MultiNode)):
|
|
2450
2449
|
for b in block.nodes:
|
|
@@ -2474,7 +2473,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2474
2473
|
graph.remove_edge(src, succ)
|
|
2475
2474
|
|
|
2476
2475
|
@staticmethod
|
|
2477
|
-
def _remove_first_statement_if_jump(node:
|
|
2476
|
+
def _remove_first_statement_if_jump(node: BaseNode | Block) -> Jump | ConditionalJump | None:
|
|
2478
2477
|
if isinstance(node, Block):
|
|
2479
2478
|
if node.statements:
|
|
2480
2479
|
idx = 0
|
|
@@ -2503,7 +2502,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2503
2502
|
return None
|
|
2504
2503
|
|
|
2505
2504
|
@staticmethod
|
|
2506
|
-
def _chick_order_edges(edges:
|
|
2505
|
+
def _chick_order_edges(edges: list, node_seq: dict[Any, int]) -> list:
|
|
2507
2506
|
graph = networkx.DiGraph()
|
|
2508
2507
|
graph.add_edges_from(edges)
|
|
2509
2508
|
|
|
@@ -2520,7 +2519,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2520
2519
|
return list(sorted(edges, key=_sort_edge, reverse=True))
|
|
2521
2520
|
|
|
2522
2521
|
@staticmethod
|
|
2523
|
-
def _replace_node_in_edge_list(edge_list:
|
|
2522
|
+
def _replace_node_in_edge_list(edge_list: list[tuple], old_node, new_node) -> None:
|
|
2524
2523
|
for idx in range(len(edge_list)): # pylint:disable=consider-using-enumerate
|
|
2525
2524
|
edge = edge_list[idx]
|
|
2526
2525
|
src, dst = edge
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import itertools
|
|
2
|
-
from typing import Optional,
|
|
2
|
+
from typing import Optional, TYPE_CHECKING
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
import networkx
|
|
@@ -33,7 +33,7 @@ class RecursiveStructurer(Analysis):
|
|
|
33
33
|
region,
|
|
34
34
|
cond_proc=None,
|
|
35
35
|
func: Optional["Function"] = None,
|
|
36
|
-
structurer_cls:
|
|
36
|
+
structurer_cls: type | None = None,
|
|
37
37
|
improve_structurer=True,
|
|
38
38
|
**kwargs,
|
|
39
39
|
):
|
|
@@ -51,7 +51,7 @@ class RecursiveStructurer(Analysis):
|
|
|
51
51
|
|
|
52
52
|
def _analyze(self):
|
|
53
53
|
region = self._region.recursive_copy()
|
|
54
|
-
self._case_entry_to_switch_head:
|
|
54
|
+
self._case_entry_to_switch_head: dict[int, int] = self._get_switch_case_entries()
|
|
55
55
|
self.result_incomplete = False
|
|
56
56
|
|
|
57
57
|
# visit the region in post-order DFS
|
|
@@ -149,7 +149,7 @@ class RecursiveStructurer(Analysis):
|
|
|
149
149
|
def _replace_region_with_region(parent_region, sub_region, new_region):
|
|
150
150
|
parent_region.replace_region_with_region(sub_region, new_region)
|
|
151
151
|
|
|
152
|
-
def _get_switch_case_entries(self) ->
|
|
152
|
+
def _get_switch_case_entries(self) -> dict[int, int]:
|
|
153
153
|
if self.function is None:
|
|
154
154
|
return {}
|
|
155
155
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint:disable=unused-argument
|
|
2
|
-
from typing import Optional,
|
|
2
|
+
from typing import Optional, Any, TYPE_CHECKING
|
|
3
|
+
from collections import OrderedDict as ODict
|
|
3
4
|
from collections import defaultdict, OrderedDict
|
|
4
5
|
import logging
|
|
5
6
|
|
|
@@ -50,7 +51,7 @@ class StructurerBase(Analysis):
|
|
|
50
51
|
parent_map=None,
|
|
51
52
|
condition_processor=None,
|
|
52
53
|
func: Optional["Function"] = None,
|
|
53
|
-
case_entry_to_switch_head:
|
|
54
|
+
case_entry_to_switch_head: dict[int, int] | None = None,
|
|
54
55
|
parent_region=None,
|
|
55
56
|
improve_structurer=True,
|
|
56
57
|
**kwargs,
|
|
@@ -251,7 +252,7 @@ class StructurerBase(Analysis):
|
|
|
251
252
|
if len(node.nodes) > 1:
|
|
252
253
|
for i in range(len(node.nodes) - 1):
|
|
253
254
|
this_node = node.nodes[i]
|
|
254
|
-
jump_stmt:
|
|
255
|
+
jump_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None = None
|
|
255
256
|
if (
|
|
256
257
|
isinstance(this_node, ailment.Block)
|
|
257
258
|
and this_node.statements
|
|
@@ -313,7 +314,7 @@ class StructurerBase(Analysis):
|
|
|
313
314
|
if len(node.nodes) > 1:
|
|
314
315
|
for i in range(len(node.nodes) - 1):
|
|
315
316
|
this_node = node.nodes[i]
|
|
316
|
-
jump_stmt:
|
|
317
|
+
jump_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None = None
|
|
317
318
|
if (
|
|
318
319
|
isinstance(this_node, ailment.Block)
|
|
319
320
|
and this_node.statements
|
|
@@ -387,7 +388,7 @@ class StructurerBase(Analysis):
|
|
|
387
388
|
return
|
|
388
389
|
|
|
389
390
|
# stores all nodes that will replace the current AIL Block node
|
|
390
|
-
new_nodes:
|
|
391
|
+
new_nodes: list = []
|
|
391
392
|
last_nonjump_stmt_idx = 0
|
|
392
393
|
|
|
393
394
|
# find all jump and indirect jump statements
|
|
@@ -466,7 +467,7 @@ class StructurerBase(Analysis):
|
|
|
466
467
|
walker = SequenceWalker(handlers=handlers)
|
|
467
468
|
walker.walk(loop_node)
|
|
468
469
|
|
|
469
|
-
def _rewrite_jumps_to_continues(self, loop_seq: SequenceNode, loop_node:
|
|
470
|
+
def _rewrite_jumps_to_continues(self, loop_seq: SequenceNode, loop_node: LoopNode | None = None):
|
|
470
471
|
continue_node_addr = loop_seq.addr
|
|
471
472
|
# exception: do-while with a multi-statement condition
|
|
472
473
|
if (
|
|
@@ -740,12 +741,12 @@ class StructurerBase(Analysis):
|
|
|
740
741
|
#
|
|
741
742
|
|
|
742
743
|
def _reorganize_switch_cases(
|
|
743
|
-
self, cases: ODict[
|
|
744
|
-
) -> ODict[
|
|
744
|
+
self, cases: ODict[int | tuple[int, ...], SequenceNode]
|
|
745
|
+
) -> ODict[int | tuple[int, ...], SequenceNode]:
|
|
745
746
|
new_cases = OrderedDict()
|
|
746
747
|
|
|
747
748
|
caseid2gotoaddrs = {}
|
|
748
|
-
addr2caseids:
|
|
749
|
+
addr2caseids: dict[int, list[int, tuple[int, ...]]] = defaultdict(list)
|
|
749
750
|
|
|
750
751
|
# collect goto locations
|
|
751
752
|
for idx, case_node in cases.items():
|
|
@@ -814,8 +815,8 @@ class StructurerBase(Analysis):
|
|
|
814
815
|
|
|
815
816
|
@staticmethod
|
|
816
817
|
def _remove_last_statement_if_jump(
|
|
817
|
-
node:
|
|
818
|
-
) ->
|
|
818
|
+
node: BaseNode | ailment.Block,
|
|
819
|
+
) -> ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None:
|
|
819
820
|
try:
|
|
820
821
|
last_stmts = ConditionProcessor.get_last_statements(node)
|
|
821
822
|
except EmptyBlockNotice:
|
|
@@ -878,7 +879,7 @@ class StructurerBase(Analysis):
|
|
|
878
879
|
else:
|
|
879
880
|
return SequenceNode(addr, nodes=[node_0, node_1])
|
|
880
881
|
|
|
881
|
-
def _update_new_sequences(self, removed_sequences:
|
|
882
|
+
def _update_new_sequences(self, removed_sequences: set[SequenceNode], replaced_sequences: dict[SequenceNode, Any]):
|
|
882
883
|
new_sequences = []
|
|
883
884
|
for new_seq_ in self._new_sequences:
|
|
884
885
|
if new_seq_ not in removed_sequences:
|
|
@@ -917,8 +918,8 @@ class StructurerBase(Analysis):
|
|
|
917
918
|
@staticmethod
|
|
918
919
|
def replace_node_in_node(
|
|
919
920
|
parent_node: BaseNode,
|
|
920
|
-
old_node:
|
|
921
|
-
new_node:
|
|
921
|
+
old_node: BaseNode | ailment.Block,
|
|
922
|
+
new_node: BaseNode | ailment.Block,
|
|
922
923
|
) -> None:
|
|
923
924
|
if isinstance(parent_node, SequenceNode):
|
|
924
925
|
for i in range(len(parent_node.nodes)): # pylint:disable=consider-using-enumerate
|
|
@@ -941,7 +942,7 @@ class StructurerBase(Analysis):
|
|
|
941
942
|
raise TypeError(f"Unsupported node type {type(parent_node)}")
|
|
942
943
|
|
|
943
944
|
@staticmethod
|
|
944
|
-
def is_a_jump_target(stmt:
|
|
945
|
+
def is_a_jump_target(stmt: ailment.Stmt.ConditionalJump | ailment.Stmt.Jump, addr: int) -> bool:
|
|
945
946
|
if isinstance(stmt, ailment.Stmt.ConditionalJump):
|
|
946
947
|
if isinstance(stmt.true_target, ailment.Expr.Const) and stmt.true_target.value == addr:
|
|
947
948
|
return True
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint:disable=missing-class-docstring
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any
|
|
3
|
+
from collections import OrderedDict as ODict
|
|
3
4
|
|
|
4
5
|
import claripy
|
|
5
6
|
import ailment
|
|
@@ -95,7 +96,7 @@ class BaseNode:
|
|
|
95
96
|
|
|
96
97
|
return True
|
|
97
98
|
|
|
98
|
-
addr:
|
|
99
|
+
addr: int | None
|
|
99
100
|
|
|
100
101
|
def dbg_repr(self, indent=0):
|
|
101
102
|
return " " * indent + f"## dbg_repr not implemented for {type(self).__name__}"
|
|
@@ -107,7 +108,7 @@ class SequenceNode(BaseNode):
|
|
|
107
108
|
"nodes",
|
|
108
109
|
)
|
|
109
110
|
|
|
110
|
-
def __init__(self, addr:
|
|
111
|
+
def __init__(self, addr: int | None, nodes=None):
|
|
111
112
|
self.addr = addr
|
|
112
113
|
self.nodes = nodes if nodes is not None else []
|
|
113
114
|
|
|
@@ -237,7 +238,7 @@ class CascadingConditionNode(BaseNode):
|
|
|
237
238
|
"else_node",
|
|
238
239
|
)
|
|
239
240
|
|
|
240
|
-
def __init__(self, addr, condition_and_nodes:
|
|
241
|
+
def __init__(self, addr, condition_and_nodes: list[tuple[Any, BaseNode]], else_node: BaseNode = None):
|
|
241
242
|
self.addr = addr
|
|
242
243
|
self.condition_and_nodes = condition_and_nodes
|
|
243
244
|
self.else_node = else_node
|
|
@@ -357,9 +358,9 @@ class SwitchCaseNode(BaseNode):
|
|
|
357
358
|
"addr",
|
|
358
359
|
)
|
|
359
360
|
|
|
360
|
-
def __init__(self, switch_expr, cases: ODict[
|
|
361
|
+
def __init__(self, switch_expr, cases: ODict[int | tuple[int, ...], SequenceNode], default_node, addr=None):
|
|
361
362
|
self.switch_expr = switch_expr
|
|
362
|
-
self.cases: ODict[
|
|
363
|
+
self.cases: ODict[int | tuple[int, ...], SequenceNode] = cases
|
|
363
364
|
self.default_node = default_node
|
|
364
365
|
self.addr = addr
|
|
365
366
|
|
|
@@ -372,10 +373,10 @@ class IncompleteSwitchCaseNode(BaseNode):
|
|
|
372
373
|
|
|
373
374
|
__slots__ = ("addr", "head", "cases")
|
|
374
375
|
|
|
375
|
-
def __init__(self, addr, head, cases:
|
|
376
|
+
def __init__(self, addr, head, cases: list):
|
|
376
377
|
self.addr = addr
|
|
377
378
|
self.head = head
|
|
378
|
-
self.cases:
|
|
379
|
+
self.cases: list = cases
|
|
379
380
|
|
|
380
381
|
|
|
381
382
|
#
|
|
@@ -395,7 +396,7 @@ class IncompleteSwitchCaseHeadStatement(ailment.statement.Statement):
|
|
|
395
396
|
self.switch_variable = switch_variable
|
|
396
397
|
# original cmp node, case value | "default", address of the case node, idx of the case node,
|
|
397
398
|
# address of the next cmp node
|
|
398
|
-
self.case_addrs:
|
|
399
|
+
self.case_addrs: list[tuple[ailment.Block, int | str, int, int | None, int]] = case_addrs
|
|
399
400
|
# a string representation of the addresses of all cases, used for hashing
|
|
400
401
|
self._case_addrs_str = str(sorted([c[0].addr for c in self.case_addrs if c[0] is not None]))
|
|
401
402
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# pylint:disable=wrong-import-position,broad-exception-caught,ungrouped-imports
|
|
2
2
|
import pathlib
|
|
3
3
|
import copy
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Union
|
|
5
|
+
from collections.abc import Iterable
|
|
5
6
|
import logging
|
|
6
7
|
|
|
7
8
|
import networkx
|
|
@@ -119,7 +120,7 @@ def extract_jump_targets(stmt):
|
|
|
119
120
|
return targets
|
|
120
121
|
|
|
121
122
|
|
|
122
|
-
def switch_extract_cmp_bounds(last_stmt: ailment.Stmt.ConditionalJump) ->
|
|
123
|
+
def switch_extract_cmp_bounds(last_stmt: ailment.Stmt.ConditionalJump) -> tuple[Any, int, int] | None:
|
|
123
124
|
"""
|
|
124
125
|
Check the last statement of the switch-case header node, and extract lower+upper bounds for the comparison.
|
|
125
126
|
|
|
@@ -161,7 +162,7 @@ def get_ast_subexprs(claripy_ast):
|
|
|
161
162
|
yield ast
|
|
162
163
|
|
|
163
164
|
|
|
164
|
-
def insert_node(parent, insert_location: str, node, node_idx:
|
|
165
|
+
def insert_node(parent, insert_location: str, node, node_idx: int | tuple[int] | None, label=None):
|
|
165
166
|
if insert_location not in {"before", "after"}:
|
|
166
167
|
raise ValueError('"insert_location" must be either "before" or "after"')
|
|
167
168
|
|
|
@@ -336,7 +337,7 @@ def has_nonlabel_statements(block: ailment.Block) -> bool:
|
|
|
336
337
|
return block.statements and any(not isinstance(stmt, ailment.Stmt.Label) for stmt in block.statements)
|
|
337
338
|
|
|
338
339
|
|
|
339
|
-
def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) ->
|
|
340
|
+
def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) -> ailment.Stmt.Statement | None:
|
|
340
341
|
if isinstance(block, MultiNode):
|
|
341
342
|
for n in block.nodes:
|
|
342
343
|
stmt = first_nonlabel_statement(n)
|
|
@@ -350,14 +351,14 @@ def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) -> Option
|
|
|
350
351
|
return None
|
|
351
352
|
|
|
352
353
|
|
|
353
|
-
def last_nonlabel_statement(block: ailment.Block) ->
|
|
354
|
+
def last_nonlabel_statement(block: ailment.Block) -> ailment.Stmt.Statement | None:
|
|
354
355
|
for stmt in reversed(block.statements):
|
|
355
356
|
if not isinstance(stmt, ailment.Stmt.Label):
|
|
356
357
|
return stmt
|
|
357
358
|
return None
|
|
358
359
|
|
|
359
360
|
|
|
360
|
-
def first_nonlabel_node(seq: "SequenceNode") ->
|
|
361
|
+
def first_nonlabel_node(seq: "SequenceNode") -> Union["BaseNode", ailment.Block] | None:
|
|
361
362
|
for node in seq.nodes:
|
|
362
363
|
if isinstance(node, CodeNode):
|
|
363
364
|
inner_node = node.node
|
|
@@ -421,7 +422,7 @@ def structured_node_is_simple_return(node: Union["SequenceNode", "MultiNode"], g
|
|
|
421
422
|
Returns true on any block ending in linear statements and a return.
|
|
422
423
|
"""
|
|
423
424
|
|
|
424
|
-
def _flatten_structured_node(packed_node: Union["SequenceNode", "MultiNode"]) ->
|
|
425
|
+
def _flatten_structured_node(packed_node: Union["SequenceNode", "MultiNode"]) -> list[ailment.Block]:
|
|
425
426
|
if not packed_node or not packed_node.nodes:
|
|
426
427
|
return []
|
|
427
428
|
|
|
@@ -477,8 +478,8 @@ def peephole_optimize_exprs(block, expr_opts):
|
|
|
477
478
|
v = False
|
|
478
479
|
|
|
479
480
|
def _handle_expr(
|
|
480
|
-
expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt:
|
|
481
|
-
) ->
|
|
481
|
+
expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: ailment.Stmt.Statement | None, block
|
|
482
|
+
) -> ailment.Expr.Expression | None:
|
|
482
483
|
old_expr = expr
|
|
483
484
|
|
|
484
485
|
redo = True
|
|
@@ -510,8 +511,8 @@ def peephole_optimize_exprs(block, expr_opts):
|
|
|
510
511
|
|
|
511
512
|
def peephole_optimize_expr(expr, expr_opts):
|
|
512
513
|
def _handle_expr(
|
|
513
|
-
expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt:
|
|
514
|
-
) ->
|
|
514
|
+
expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: ailment.Stmt.Statement | None, block
|
|
515
|
+
) -> ailment.Expr.Expression | None:
|
|
515
516
|
old_expr = expr
|
|
516
517
|
|
|
517
518
|
redo = True
|
|
@@ -595,7 +596,7 @@ def peephole_optimize_stmts(block, stmt_opts):
|
|
|
595
596
|
return statements, any_update
|
|
596
597
|
|
|
597
598
|
|
|
598
|
-
def match_stmt_classes(all_stmts:
|
|
599
|
+
def match_stmt_classes(all_stmts: list, idx: int, stmt_class_seq: Iterable[type]) -> bool:
|
|
599
600
|
for i, cls in enumerate(stmt_class_seq):
|
|
600
601
|
if idx + i >= len(all_stmts):
|
|
601
602
|
return False
|
|
@@ -639,7 +640,7 @@ def peephole_optimize_multistmts(block, stmt_opts):
|
|
|
639
640
|
return statements, any_update
|
|
640
641
|
|
|
641
642
|
|
|
642
|
-
def decompile_functions(path, functions=None, structurer=None, catch_errors=False) ->
|
|
643
|
+
def decompile_functions(path, functions=None, structurer=None, catch_errors=False) -> str | None:
|
|
643
644
|
"""
|
|
644
645
|
Decompile a binary into a set of functions.
|
|
645
646
|
|
|
@@ -663,7 +664,7 @@ def decompile_functions(path, functions=None, structurer=None, catch_errors=Fals
|
|
|
663
664
|
functions = list(sorted(cfg.kb.functions))
|
|
664
665
|
|
|
665
666
|
# normalize the functions that could be ints as names
|
|
666
|
-
normalized_functions:
|
|
667
|
+
normalized_functions: list[int | str] = []
|
|
667
668
|
for func in functions:
|
|
668
669
|
try:
|
|
669
670
|
if isinstance(func, str):
|
|
@@ -742,7 +743,7 @@ def find_block_by_addr(graph: networkx.DiGraph, addr: int):
|
|
|
742
743
|
raise KeyError("The block is not in the graph!")
|
|
743
744
|
|
|
744
745
|
|
|
745
|
-
def sequence_to_blocks(seq: "BaseNode") ->
|
|
746
|
+
def sequence_to_blocks(seq: "BaseNode") -> list[ailment.Block]:
|
|
746
747
|
"""
|
|
747
748
|
Converts a sequence node (BaseNode) to a list of ailment blocks contained in it and all its children.
|
|
748
749
|
"""
|
|
@@ -753,7 +754,7 @@ def sequence_to_blocks(seq: "BaseNode") -> List[ailment.Block]:
|
|
|
753
754
|
|
|
754
755
|
def sequence_to_statements(
|
|
755
756
|
seq: "BaseNode", exclude=(ailment.statement.Jump, ailment.statement.Jump)
|
|
756
|
-
) ->
|
|
757
|
+
) -> list[ailment.statement.Statement]:
|
|
757
758
|
"""
|
|
758
759
|
Converts a sequence node (BaseNode) to a list of ailment Statements contained in it and all its children.
|
|
759
760
|
May exclude certain types of statements.
|