angr 9.2.101__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.

Files changed (239) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +7 -6
  3. angr/analyses/calling_convention.py +33 -35
  4. angr/analyses/cdg.py +2 -4
  5. angr/analyses/cfg/cfb.py +4 -3
  6. angr/analyses/cfg/cfg_base.py +14 -14
  7. angr/analyses/cfg/cfg_emulated.py +3 -4
  8. angr/analyses/cfg/cfg_fast.py +46 -46
  9. angr/analyses/cfg/cfg_fast_soot.py +1 -2
  10. angr/analyses/cfg/cfg_job_base.py +2 -2
  11. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +14 -13
  12. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +5 -5
  13. angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +3 -3
  14. angr/analyses/complete_calling_conventions.py +13 -12
  15. angr/analyses/data_dep/data_dependency_analysis.py +24 -24
  16. angr/analyses/data_dep/dep_nodes.py +3 -3
  17. angr/analyses/ddg.py +1 -2
  18. angr/analyses/decompiler/ail_simplifier.py +35 -34
  19. angr/analyses/decompiler/block_io_finder.py +20 -20
  20. angr/analyses/decompiler/block_similarity.py +4 -6
  21. angr/analyses/decompiler/block_simplifier.py +17 -16
  22. angr/analyses/decompiler/callsite_maker.py +25 -10
  23. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -3
  24. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +2 -4
  25. angr/analyses/decompiler/clinic.py +250 -45
  26. angr/analyses/decompiler/condition_processor.py +15 -8
  27. angr/analyses/decompiler/decompilation_cache.py +7 -7
  28. angr/analyses/decompiler/decompilation_options.py +4 -4
  29. angr/analyses/decompiler/decompiler.py +19 -15
  30. angr/analyses/decompiler/expression_counters.py +10 -9
  31. angr/analyses/decompiler/goto_manager.py +2 -4
  32. angr/analyses/decompiler/graph_region.py +9 -9
  33. angr/analyses/decompiler/jump_target_collector.py +1 -2
  34. angr/analyses/decompiler/optimization_passes/__init__.py +4 -3
  35. angr/analyses/decompiler/optimization_passes/code_motion.py +5 -6
  36. angr/analyses/decompiler/optimization_passes/const_derefs.py +4 -4
  37. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +73 -0
  38. angr/analyses/decompiler/optimization_passes/engine_base.py +25 -3
  39. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +6 -5
  40. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
  41. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +3 -0
  42. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +2 -2
  43. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +17 -17
  44. angr/analyses/decompiler/optimization_passes/optimization_pass.py +12 -13
  45. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +25 -21
  46. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +3 -3
  47. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +1 -2
  48. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +7 -7
  49. angr/analyses/decompiler/optimization_passes/spilled_register_finder.py +18 -0
  50. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -3
  51. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -2
  52. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +2 -2
  53. angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -3
  54. angr/analyses/decompiler/peephole_optimizations/base.py +13 -15
  55. angr/analyses/decompiler/peephole_optimizations/bswap.py +1 -3
  56. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +72 -0
  57. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -2
  58. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
  59. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +5 -10
  60. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +3 -4
  61. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +7 -10
  62. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +2 -3
  63. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -2
  64. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +4 -4
  65. angr/analyses/decompiler/redundant_label_remover.py +4 -5
  66. angr/analyses/decompiler/region_identifier.py +4 -5
  67. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -2
  68. angr/analyses/decompiler/region_simplifiers/expr_folding.py +19 -20
  69. angr/analyses/decompiler/region_simplifiers/goto.py +2 -3
  70. angr/analyses/decompiler/region_simplifiers/loop.py +1 -2
  71. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -2
  72. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +1 -3
  73. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +19 -19
  74. angr/analyses/decompiler/return_maker.py +1 -2
  75. angr/analyses/decompiler/structured_codegen/base.py +5 -6
  76. angr/analyses/decompiler/structured_codegen/c.py +39 -38
  77. angr/analyses/decompiler/structuring/__init__.py +1 -1
  78. angr/analyses/decompiler/structuring/dream.py +17 -16
  79. angr/analyses/decompiler/structuring/phoenix.py +45 -46
  80. angr/analyses/decompiler/structuring/recursive_structurer.py +4 -4
  81. angr/analyses/decompiler/structuring/structurer_base.py +16 -15
  82. angr/analyses/decompiler/structuring/structurer_nodes.py +10 -9
  83. angr/analyses/decompiler/utils.py +17 -16
  84. angr/analyses/disassembly.py +7 -6
  85. angr/analyses/flirt.py +9 -9
  86. angr/analyses/forward_analysis/forward_analysis.py +15 -14
  87. angr/analyses/forward_analysis/visitors/function_graph.py +1 -2
  88. angr/analyses/forward_analysis/visitors/graph.py +16 -15
  89. angr/analyses/propagator/engine_ail.py +30 -26
  90. angr/analyses/propagator/outdated_definition_walker.py +8 -7
  91. angr/analyses/propagator/propagator.py +11 -13
  92. angr/analyses/proximity_graph.py +21 -21
  93. angr/analyses/reaching_definitions/__init__.py +3 -3
  94. angr/analyses/reaching_definitions/call_trace.py +3 -6
  95. angr/analyses/reaching_definitions/dep_graph.py +41 -48
  96. angr/analyses/reaching_definitions/engine_ail.py +11 -5
  97. angr/analyses/reaching_definitions/engine_vex.py +9 -8
  98. angr/analyses/reaching_definitions/function_handler.py +51 -34
  99. angr/analyses/reaching_definitions/heap_allocator.py +3 -4
  100. angr/analyses/reaching_definitions/rd_initializer.py +8 -8
  101. angr/analyses/reaching_definitions/rd_state.py +57 -58
  102. angr/analyses/reaching_definitions/reaching_definitions.py +18 -17
  103. angr/analyses/reaching_definitions/subject.py +2 -3
  104. angr/analyses/stack_pointer_tracker.py +15 -6
  105. angr/analyses/typehoon/dfa.py +4 -4
  106. angr/analyses/typehoon/simple_solver.py +48 -52
  107. angr/analyses/typehoon/translator.py +3 -6
  108. angr/analyses/typehoon/typeconsts.py +13 -14
  109. angr/analyses/typehoon/typehoon.py +9 -9
  110. angr/analyses/typehoon/typevars.py +18 -17
  111. angr/analyses/variable_recovery/engine_ail.py +5 -5
  112. angr/analyses/variable_recovery/engine_base.py +25 -21
  113. angr/analyses/variable_recovery/irsb_scanner.py +8 -9
  114. angr/analyses/variable_recovery/variable_recovery.py +1 -2
  115. angr/analyses/variable_recovery/variable_recovery_base.py +14 -13
  116. angr/analyses/variable_recovery/variable_recovery_fast.py +8 -8
  117. angr/analyses/veritesting.py +1 -2
  118. angr/analyses/vfg.py +57 -56
  119. angr/analyses/xrefs.py +1 -2
  120. angr/angrdb/db.py +7 -7
  121. angr/angrdb/serializers/kb.py +16 -13
  122. angr/angrdb/serializers/loader.py +1 -2
  123. angr/angrdb/serializers/structured_code.py +2 -2
  124. angr/annocfg.py +1 -2
  125. angr/block.py +16 -6
  126. angr/calling_conventions.py +27 -27
  127. angr/code_location.py +8 -8
  128. angr/codenode.py +1 -2
  129. angr/concretization_strategies/max.py +1 -3
  130. angr/distributed/server.py +1 -3
  131. angr/distributed/worker.py +1 -2
  132. angr/engines/engine.py +2 -3
  133. angr/engines/light/engine.py +4 -4
  134. angr/engines/pcode/behavior.py +20 -2
  135. angr/engines/pcode/emulate.py +1 -1
  136. angr/engines/pcode/engine.py +7 -7
  137. angr/engines/pcode/lifter.py +78 -77
  138. angr/engines/vex/claripy/ccall.py +1 -2
  139. angr/engines/vex/claripy/datalayer.py +1 -2
  140. angr/engines/vex/light/light.py +1 -2
  141. angr/exploration_techniques/tracer.py +4 -4
  142. angr/factory.py +12 -15
  143. angr/flirt/__init__.py +8 -8
  144. angr/flirt/build_sig.py +2 -3
  145. angr/keyed_region.py +2 -2
  146. angr/knowledge_base/knowledge_base.py +3 -3
  147. angr/knowledge_plugins/callsite_prototypes.py +4 -6
  148. angr/knowledge_plugins/cfg/cfg_manager.py +19 -6
  149. angr/knowledge_plugins/cfg/cfg_model.py +26 -27
  150. angr/knowledge_plugins/cfg/cfg_node.py +2 -2
  151. angr/knowledge_plugins/cfg/indirect_jump.py +6 -8
  152. angr/knowledge_plugins/cfg/memory_data.py +8 -9
  153. angr/knowledge_plugins/custom_strings.py +1 -3
  154. angr/knowledge_plugins/debug_variables.py +2 -2
  155. angr/knowledge_plugins/functions/function.py +21 -22
  156. angr/knowledge_plugins/functions/function_manager.py +5 -5
  157. angr/knowledge_plugins/indirect_jumps.py +1 -3
  158. angr/knowledge_plugins/key_definitions/atoms.py +7 -7
  159. angr/knowledge_plugins/key_definitions/definition.py +14 -14
  160. angr/knowledge_plugins/key_definitions/environment.py +5 -7
  161. angr/knowledge_plugins/key_definitions/heap_address.py +1 -3
  162. angr/knowledge_plugins/key_definitions/key_definition_manager.py +3 -2
  163. angr/knowledge_plugins/key_definitions/live_definitions.py +60 -59
  164. angr/knowledge_plugins/key_definitions/liveness.py +16 -16
  165. angr/knowledge_plugins/key_definitions/rd_model.py +15 -15
  166. angr/knowledge_plugins/key_definitions/uses.py +11 -11
  167. angr/knowledge_plugins/patches.py +4 -8
  168. angr/knowledge_plugins/propagations/prop_value.py +10 -9
  169. angr/knowledge_plugins/propagations/propagation_manager.py +3 -5
  170. angr/knowledge_plugins/propagations/propagation_model.py +9 -9
  171. angr/knowledge_plugins/propagations/states.py +52 -22
  172. angr/knowledge_plugins/structured_code/manager.py +2 -2
  173. angr/knowledge_plugins/sync/sync_controller.py +3 -3
  174. angr/knowledge_plugins/variables/variable_access.py +4 -4
  175. angr/knowledge_plugins/variables/variable_manager.py +56 -39
  176. angr/knowledge_plugins/xrefs/xref.py +9 -11
  177. angr/knowledge_plugins/xrefs/xref_manager.py +3 -4
  178. angr/misc/ansi.py +1 -2
  179. angr/misc/autoimport.py +3 -3
  180. angr/misc/plugins.py +9 -9
  181. angr/procedures/definitions/__init__.py +16 -16
  182. angr/procedures/definitions/linux_kernel.py +1 -1
  183. angr/procedures/definitions/parse_win32json.py +1 -1
  184. angr/procedures/java_jni/__init__.py +1 -1
  185. angr/procedures/java_jni/array_operations.py +1 -2
  186. angr/procedures/java_jni/method_calls.py +1 -2
  187. angr/procedures/posix/inet_ntoa.py +1 -2
  188. angr/procedures/stubs/format_parser.py +3 -3
  189. angr/project.py +13 -11
  190. angr/sim_manager.py +12 -12
  191. angr/sim_procedure.py +7 -3
  192. angr/sim_state.py +2 -2
  193. angr/sim_type.py +60 -45
  194. angr/sim_variable.py +5 -5
  195. angr/simos/simos.py +1 -2
  196. angr/simos/userland.py +1 -2
  197. angr/state_plugins/callstack.py +3 -2
  198. angr/state_plugins/history.py +1 -2
  199. angr/state_plugins/solver.py +34 -34
  200. angr/storage/memory_mixins/__init__.py +4 -3
  201. angr/storage/memory_mixins/actions_mixin.py +1 -3
  202. angr/storage/memory_mixins/address_concretization_mixin.py +1 -3
  203. angr/storage/memory_mixins/convenient_mappings_mixin.py +3 -4
  204. angr/storage/memory_mixins/default_filler_mixin.py +1 -1
  205. angr/storage/memory_mixins/label_merger_mixin.py +2 -2
  206. angr/storage/memory_mixins/multi_value_merger_mixin.py +4 -3
  207. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +9 -8
  208. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +12 -11
  209. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +8 -8
  210. angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +2 -3
  211. angr/storage/memory_mixins/paged_memory/pages/list_page.py +10 -11
  212. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +11 -10
  213. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +18 -17
  214. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +12 -11
  215. angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +3 -3
  216. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +3 -2
  217. angr/storage/memory_mixins/regioned_memory/region_data.py +1 -2
  218. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +2 -2
  219. angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +3 -3
  220. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +18 -21
  221. angr/storage/memory_mixins/size_resolution_mixin.py +1 -2
  222. angr/storage/memory_mixins/symbolic_merger_mixin.py +3 -2
  223. angr/storage/memory_mixins/top_merger_mixin.py +3 -2
  224. angr/storage/memory_object.py +2 -4
  225. angr/utils/algo.py +3 -2
  226. angr/utils/dynamic_dictlist.py +5 -5
  227. angr/utils/formatting.py +4 -4
  228. angr/utils/funcid.py +1 -2
  229. angr/utils/graph.py +5 -6
  230. angr/utils/library.py +5 -5
  231. angr/utils/mp.py +5 -4
  232. angr/utils/segment_list.py +3 -4
  233. angr/utils/typing.py +3 -2
  234. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
  235. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/RECORD +239 -236
  236. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
  237. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
  238. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
  239. {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,12 @@
1
+ from __future__ import annotations
1
2
  import copy
2
3
  from collections import defaultdict, namedtuple
3
4
  import logging
4
5
  import enum
5
6
  from dataclasses import dataclass
6
- from typing import Dict, List, Tuple, Set, Optional, Iterable, Union, Type, Any, NamedTuple, TYPE_CHECKING
7
+ from typing import Any, NamedTuple, TYPE_CHECKING
8
+
9
+ from collections.abc import Iterable
7
10
 
8
11
  import networkx
9
12
  import capstone
@@ -26,6 +29,7 @@ from ...sim_type import (
26
29
  SimTypeFloat,
27
30
  SimTypePointer,
28
31
  )
32
+ from ..stack_pointer_tracker import Register, OffsetVal
29
33
  from ...sim_variable import SimVariable, SimStackVariable, SimRegisterVariable, SimMemoryVariable
30
34
  from ...knowledge_plugins.key_definitions.constants import OP_BEFORE
31
35
  from ...procedures.stubs.UnresolvableCallTarget import UnresolvableCallTarget
@@ -39,6 +43,8 @@ from .optimization_passes import (
39
43
  get_default_optimization_passes,
40
44
  OptimizationPassStage,
41
45
  RegisterSaveAreaSimplifier,
46
+ StackCanarySimplifier,
47
+ SpilledRegisterFinder,
42
48
  DUPLICATING_OPTS,
43
49
  CONDENSING_OPTS,
44
50
  )
@@ -92,15 +98,19 @@ class Clinic(Analysis):
92
98
  insert_labels=True,
93
99
  optimization_passes=None,
94
100
  cfg=None,
95
- peephole_optimizations: Optional[
96
- Iterable[Union[Type["PeepholeOptimizationStmtBase"], Type["PeepholeOptimizationExprBase"]]]
97
- ] = None, # pylint:disable=line-too-long
98
- must_struct: Optional[Set[str]] = None,
101
+ peephole_optimizations: None | (
102
+ Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
103
+ ) = None, # pylint:disable=line-too-long
104
+ must_struct: set[str] | None = None,
99
105
  variable_kb=None,
100
106
  reset_variable_names=False,
101
107
  rewrite_ites_to_diamonds=True,
102
- cache: Optional["DecompilationCache"] = None,
108
+ cache: DecompilationCache | None = None,
103
109
  mode: ClinicMode = ClinicMode.DECOMPILE,
110
+ sp_shift: int = 0,
111
+ inline_functions: set[Function] | None = frozenset(),
112
+ inlined_counts: dict[int, int] | None = None,
113
+ inlining_parents: set[int] | None = None,
104
114
  ):
105
115
  if not func.normalized and mode == ClinicMode.DECOMPILE:
106
116
  raise ValueError("Decompilation must work on normalized function graphs.")
@@ -108,14 +118,14 @@ class Clinic(Analysis):
108
118
  self.function = func
109
119
 
110
120
  self.graph = None
111
- self.cc_graph: Optional[networkx.DiGraph] = None
112
- self.unoptimized_graph: Optional[networkx.DiGraph] = None
121
+ self.cc_graph: networkx.DiGraph | None = None
122
+ self.unoptimized_graph: networkx.DiGraph | None = None
113
123
  self.arg_list = None
114
124
  self.variable_kb = variable_kb
115
- self.externs: Set[SimMemoryVariable] = set()
116
- self.data_refs: Dict[int, int] = {} # data address to instruction address
125
+ self.externs: set[SimMemoryVariable] = set()
126
+ self.data_refs: dict[int, int] = {} # data address to instruction address
117
127
 
118
- self._func_graph: Optional[networkx.DiGraph] = None
128
+ self._func_graph: networkx.DiGraph | None = None
119
129
  self._ail_manager = None
120
130
  self._blocks_by_addr_and_size = {}
121
131
 
@@ -124,15 +134,22 @@ class Clinic(Analysis):
124
134
  self._remove_dead_memdefs = remove_dead_memdefs
125
135
  self._exception_edges = exception_edges
126
136
  self._sp_tracker_track_memory = sp_tracker_track_memory
127
- self._cfg: Optional["CFGModel"] = cfg
137
+ self._cfg: CFGModel | None = cfg
128
138
  self.peephole_optimizations = peephole_optimizations
129
139
  self._must_struct = must_struct
130
140
  self._reset_variable_names = reset_variable_names
131
141
  self._rewrite_ites_to_diamonds = rewrite_ites_to_diamonds
132
- self.reaching_definitions: Optional[ReachingDefinitionsAnalysis] = None
142
+ self.reaching_definitions: ReachingDefinitionsAnalysis | None = None
133
143
  self._cache = cache
134
144
  self._mode = mode
135
145
 
146
+ # inlining help
147
+ self._sp_shift = sp_shift
148
+ self._max_stack_depth = 0
149
+ self._inline_functions = inline_functions
150
+ self._inlined_counts = {} if inlined_counts is None else inlined_counts
151
+ self._inlining_parents = inlining_parents or ()
152
+
136
153
  self._register_save_areas_removed: bool = False
137
154
 
138
155
  self._new_block_addrs = set()
@@ -190,6 +207,18 @@ class Clinic(Analysis):
190
207
  #
191
208
 
192
209
  def _analyze_for_decompiling(self):
210
+ if not (ail_graph := self._decompilation_graph_recovery()):
211
+ return
212
+ ail_graph = self._decompilation_fixups(ail_graph)
213
+
214
+ if self._inline_functions:
215
+ self._max_stack_depth += self.calculate_stack_depth()
216
+ ail_graph = self._inline_child_functions(ail_graph)
217
+
218
+ ail_graph = self._decompilation_simplifications(ail_graph)
219
+ self.graph = ail_graph
220
+
221
+ def _decompilation_graph_recovery(self):
193
222
  is_pcode_arch = ":" in self.project.arch.name
194
223
 
195
224
  # Set up the function graph according to configurations
@@ -202,7 +231,7 @@ class Clinic(Analysis):
202
231
 
203
232
  # if the graph is empty, don't continue
204
233
  if not self._func_graph:
205
- return
234
+ return None
206
235
 
207
236
  # Make sure calling conventions of all functions that the current function calls have been recovered
208
237
  if not is_pcode_arch:
@@ -212,16 +241,16 @@ class Clinic(Analysis):
212
241
  # initialize the AIL conversion manager
213
242
  self._ail_manager = ailment.Manager(arch=self.project.arch)
214
243
 
215
- # Track stack pointers
216
- self._update_progress(15.0, text="Tracking stack pointers")
217
- spt = self._track_stack_pointers()
218
-
219
244
  # Convert VEX blocks to AIL blocks and then simplify them
220
245
 
221
246
  self._update_progress(20.0, text="Converting VEX to AIL")
222
247
  self._convert_all()
223
248
 
224
- ail_graph = self._make_ailgraph()
249
+ return self._make_ailgraph()
250
+
251
+ def _decompilation_fixups(self, ail_graph):
252
+ is_pcode_arch = ":" in self.project.arch.name
253
+
225
254
  if self._rewrite_ites_to_diamonds:
226
255
  self._rewrite_ite_expressions(ail_graph)
227
256
  self._remove_redundant_jump_blocks(ail_graph)
@@ -244,6 +273,127 @@ class Clinic(Analysis):
244
273
  self._update_progress(29.0, text="Recovering calling conventions (AIL mode)")
245
274
  self._recover_calling_conventions(func_graph=ail_graph)
246
275
 
276
+ return ail_graph
277
+
278
+ def _inline_child_functions(self, ail_graph):
279
+ for blk in ail_graph.nodes():
280
+ for idx, stmt in enumerate(blk.statements):
281
+ if isinstance(stmt, ailment.Stmt.Call) and isinstance(stmt.target, ailment.Expr.Const):
282
+ callee = self.function._function_manager.function(stmt.target.value)
283
+ if (
284
+ callee.addr == self.function.addr
285
+ or callee.addr in self._inlining_parents
286
+ or callee not in self._inline_functions
287
+ or callee.is_plt
288
+ or callee.is_simprocedure
289
+ ):
290
+ continue
291
+
292
+ ail_graph = self._inline_call(ail_graph, blk, idx, callee)
293
+ return ail_graph
294
+
295
+ def _inline_call(self, ail_graph, caller_block, call_idx, callee):
296
+ callee_clinic = self.project.analyses.Clinic(
297
+ callee,
298
+ mode=ClinicMode.DECOMPILE,
299
+ inline_functions=self._inline_functions,
300
+ inlining_parents=self._inlining_parents + (self.function.addr,),
301
+ inlined_counts=self._inlined_counts,
302
+ optimization_passes=[StackCanarySimplifier, SpilledRegisterFinder],
303
+ sp_shift=self._max_stack_depth,
304
+ )
305
+ self._max_stack_depth = callee_clinic._max_stack_depth
306
+ callee_graph = callee_clinic.copy_graph()
307
+
308
+ # uniquely mark all the blocks in case of duplicates (e.g., foo(); foo();)
309
+ self._inlined_counts.setdefault(callee.addr, 0)
310
+ for blk in callee_graph.nodes():
311
+ blk.idx = self._inlined_counts[callee.addr]
312
+ self._inlined_counts[callee.addr] += 1
313
+
314
+ # figure out where the callee should start at and return to
315
+ callee_start = next(n for n in callee_graph if n.addr == callee.addr)
316
+ caller_successors = list(ail_graph.out_edges(caller_block, data=True))
317
+ assert len(caller_successors) == 1
318
+ caller_successor = caller_successors[0][1]
319
+ ail_graph.remove_edge(caller_block, caller_successor)
320
+
321
+ # update all callee return nodes with caller successor
322
+ # and rewrite pseudoreg-tagged spills to actually use pseudoregs
323
+ ail_graph = networkx.union(ail_graph, callee_graph)
324
+ for blk in callee_graph.nodes():
325
+ for idx, stmt in enumerate(list(blk.statements)):
326
+ if isinstance(stmt, ailment.Stmt.Return):
327
+ blk.statements[idx] = ailment.Stmt.Jump(
328
+ None,
329
+ ailment.Expr.Const(None, None, caller_successor.addr, self.project.arch.bits),
330
+ caller_successor.idx,
331
+ **blk.statements[idx].tags,
332
+ )
333
+ blk.statements.pop(idx)
334
+ ail_graph.add_edge(blk, caller_successor)
335
+ break
336
+ if "pseudoreg" in stmt.tags and isinstance(stmt, ailment.Stmt.Store):
337
+ new_stmt = ailment.Stmt.Assignment(
338
+ stmt.idx, ailment.Expr.Register(None, None, stmt.pseudoreg, stmt.size * 8), stmt.data
339
+ )
340
+ new_stmt.tags.update(stmt.tags)
341
+ new_stmt.tags.pop("pseudoreg")
342
+ blk.statements[idx] = new_stmt
343
+ if "pseudoreg" in stmt.tags and isinstance(stmt, ailment.Stmt.Assignment):
344
+ new_stmt = ailment.Stmt.Assignment(
345
+ stmt.idx, stmt.dst, ailment.Expr.Register(None, None, stmt.pseudoreg, stmt.src.size * 8)
346
+ )
347
+ new_stmt.tags.update(stmt.tags)
348
+ new_stmt.tags.pop("pseudoreg")
349
+ blk.statements[idx] = new_stmt
350
+
351
+ # update the call edge
352
+ caller_block.statements[call_idx] = ailment.Stmt.Jump(
353
+ None,
354
+ ailment.Expr.Const(None, None, callee.addr, self.project.arch.bits),
355
+ callee_start.idx,
356
+ **caller_block.statements[call_idx].tags,
357
+ )
358
+ if (
359
+ isinstance(caller_block.statements[call_idx - 2], ailment.Stmt.Store)
360
+ and caller_block.statements[call_idx - 2].data.value == caller_successor.addr
361
+ ):
362
+ # don't push the return address
363
+ caller_block.statements.pop(call_idx - 5) # t6 = rsp<8>
364
+ caller_block.statements.pop(call_idx - 5) # t5 = (t6 - 0x8<64>)
365
+ caller_block.statements.pop(call_idx - 5) # rsp<8> = t5
366
+ caller_block.statements.pop(
367
+ call_idx - 5
368
+ ) # STORE(addr=t5, data=0x40121b<64>, size=8, endness=Iend_LE, guard=None)
369
+ caller_block.statements.pop(call_idx - 5) # t7 = (t5 - 0x80<64>) <- wtf is this??
370
+ elif (
371
+ isinstance(caller_block.statements[call_idx - 1], ailment.Stmt.Store)
372
+ and caller_block.statements[call_idx - 1].addr.base == "stack_base"
373
+ and caller_block.statements[call_idx - 1].data.value == caller_successor.addr
374
+ ):
375
+ caller_block.statements.pop(call_idx - 1) # s_10 =L 0x401225<64><8>
376
+ ail_graph.add_edge(caller_block, callee_start)
377
+
378
+ return ail_graph
379
+
380
+ def calculate_stack_depth(self):
381
+ # we need to reserve space for our own stack
382
+ spt = self._track_stack_pointers()
383
+ stack_offsets = spt.offsets_for(self.project.arch.sp_offset)
384
+ if max(stack_offsets) > 2 ** (self.project.arch.bits - 1):
385
+ # why is this unsigned...
386
+ depth = min(s for s in stack_offsets if s > 2 ** (self.project.arch.bits - 1)) - 2**self.project.arch.bits
387
+ else:
388
+ depth = min(stack_offsets)
389
+
390
+ if spt.inconsistent_for(self.project.arch.sp_offset):
391
+ l.warning("Inconsistency found during stack pointer tracking. Stack depth may be incorrect.")
392
+ depth -= 0x1000
393
+
394
+ return depth
395
+
396
+ def _decompilation_simplifications(self, ail_graph):
247
397
  # Make returns
248
398
  self._update_progress(30.0, text="Making return sites")
249
399
  if self.function.prototype is None or not isinstance(self.function.prototype.returnty, SimTypeBottom):
@@ -262,7 +412,11 @@ class Clinic(Analysis):
262
412
  )
263
413
 
264
414
  # cached block-level reaching definition analysis results and propagator results
265
- block_simplification_cache: Optional[Dict[ailment.Block, NamedTuple]] = {}
415
+ block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
416
+
417
+ # Track stack pointers
418
+ self._update_progress(15.0, text="Tracking stack pointers")
419
+ spt = self._track_stack_pointers()
266
420
 
267
421
  # Simplify blocks
268
422
  # we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
@@ -373,11 +527,11 @@ class Clinic(Analysis):
373
527
  # remove empty nodes from the graph
374
528
  ail_graph = self.remove_empty_nodes(ail_graph)
375
529
 
376
- self.graph = ail_graph
377
530
  self.arg_list = arg_list
378
531
  self.variable_kb = variable_kb
379
- self.cc_graph = self.copy_graph()
532
+ self.cc_graph = self.copy_graph(ail_graph)
380
533
  self.externs = self._collect_externs(ail_graph, variable_kb)
534
+ return ail_graph
381
535
 
382
536
  def _analyze_for_data_refs(self):
383
537
  # Set up the function graph according to configurations
@@ -404,6 +558,20 @@ class Clinic(Analysis):
404
558
  self._update_progress(20.0, text="Converting VEX to AIL")
405
559
  self._convert_all()
406
560
 
561
+ # there must be at least one Load or one Store
562
+ found_load_or_store = False
563
+ for ail_block in self._blocks_by_addr_and_size.values():
564
+ for stmt in ail_block.statements:
565
+ if isinstance(stmt, ailment.Stmt.Store):
566
+ found_load_or_store = True
567
+ break
568
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.Load):
569
+ found_load_or_store = True
570
+ break
571
+ if not found_load_or_store:
572
+ self.data_refs = {}
573
+ return
574
+
407
575
  ail_graph = self._make_ailgraph()
408
576
  self._remove_redundant_jump_blocks(ail_graph)
409
577
 
@@ -420,7 +588,7 @@ class Clinic(Analysis):
420
588
  )
421
589
 
422
590
  # cached block-level reaching definition analysis results and propagator results
423
- block_simplification_cache: Optional[Dict[ailment.Block, NamedTuple]] = {}
591
+ block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
424
592
 
425
593
  # Simplify blocks
426
594
  # we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
@@ -438,6 +606,8 @@ class Clinic(Analysis):
438
606
  unify_variables=False,
439
607
  narrow_expressions=False,
440
608
  fold_callexprs_into_conditions=False,
609
+ rewrite_ccalls=False,
610
+ max_iterations=1,
441
611
  )
442
612
 
443
613
  # clear _blocks_by_addr_and_size so no one can use it again
@@ -449,7 +619,7 @@ class Clinic(Analysis):
449
619
  self.variable_kb = None
450
620
  self.cc_graph = None
451
621
  self.externs = None
452
- self.data_refs: Dict[int, List[DataRefDesc]] = self._collect_data_refs(ail_graph)
622
+ self.data_refs: dict[int, list[DataRefDesc]] = self._collect_data_refs(ail_graph)
453
623
 
454
624
  @staticmethod
455
625
  def _copy_graph(graph: networkx.DiGraph) -> networkx.DiGraph:
@@ -475,8 +645,8 @@ class Clinic(Analysis):
475
645
  graph_copy.add_edge(new_src, new_dst, **data)
476
646
  return graph_copy
477
647
 
478
- def copy_graph(self) -> networkx.DiGraph:
479
- return self._copy_graph(self.graph)
648
+ def copy_graph(self, graph=None) -> networkx.DiGraph:
649
+ return self._copy_graph(graph or self.graph)
480
650
 
481
651
  @timethis
482
652
  def _set_function_graph(self):
@@ -618,14 +788,27 @@ class Clinic(Analysis):
618
788
  """
619
789
 
620
790
  regs = {self.project.arch.sp_offset}
791
+ initial_reg_values = {
792
+ self.project.arch.sp_offset: OffsetVal(
793
+ Register(self.project.arch.sp_offset, self.project.arch.bits), self._sp_shift
794
+ )
795
+ }
621
796
  if hasattr(self.project.arch, "bp_offset") and self.project.arch.bp_offset is not None:
622
797
  regs.add(self.project.arch.bp_offset)
798
+ initial_reg_values[self.project.arch.bp_offset] = OffsetVal(
799
+ Register(self.project.arch.bp_offset, self.project.arch.bits), self._sp_shift
800
+ )
623
801
 
624
802
  regs |= self._find_regs_compared_against_sp(self._func_graph)
625
803
 
626
804
  spt = self.project.analyses.StackPointerTracker(
627
- self.function, regs, track_memory=self._sp_tracker_track_memory, cross_insn_opt=False
805
+ self.function,
806
+ regs,
807
+ track_memory=self._sp_tracker_track_memory,
808
+ cross_insn_opt=False,
809
+ initial_reg_values=initial_reg_values,
628
810
  )
811
+
629
812
  if spt.inconsistent_for(self.project.arch.sp_offset):
630
813
  l.warning("Inconsistency found during stack pointer tracking. Decompilation results might be incorrect.")
631
814
  return spt
@@ -642,6 +825,18 @@ class Clinic(Analysis):
642
825
  ail_block = self._convert(block_node)
643
826
 
644
827
  if type(ail_block) is ailment.Block:
828
+ # remove constant pc assignments
829
+ ail_block.statements = [
830
+ stmt
831
+ for stmt in ail_block.statements
832
+ if not (
833
+ isinstance(stmt, ailment.Stmt.Assignment)
834
+ and isinstance(stmt.dst, ailment.Expr.Register)
835
+ and stmt.dst.reg_offset == self.project.arch.ip_offset
836
+ and isinstance(stmt.src, ailment.Expr.Const)
837
+ )
838
+ ]
839
+
645
840
  self._blocks_by_addr_and_size[(block_node.addr, block_node.size)] = ail_block
646
841
 
647
842
  def _convert(self, block_node):
@@ -780,7 +975,7 @@ class Clinic(Analysis):
780
975
  ail_graph: networkx.DiGraph,
781
976
  remove_dead_memdefs=False,
782
977
  stack_pointer_tracker=None,
783
- cache: Optional[Dict[ailment.Block, NamedTuple]] = None,
978
+ cache: dict[ailment.Block, NamedTuple] | None = None,
784
979
  ):
785
980
  """
786
981
  Simplify all blocks in self._blocks.
@@ -792,7 +987,7 @@ class Clinic(Analysis):
792
987
  :return: None
793
988
  """
794
989
 
795
- blocks_by_addr_and_idx: Dict[Tuple[int, Optional[int]], ailment.Block] = {}
990
+ blocks_by_addr_and_idx: dict[tuple[int, int | None], ailment.Block] = {}
796
991
 
797
992
  for ail_block in ail_graph.nodes():
798
993
  simplified = self._simplify_block(
@@ -860,6 +1055,7 @@ class Clinic(Analysis):
860
1055
  narrow_expressions=False,
861
1056
  only_consts=False,
862
1057
  fold_callexprs_into_conditions=False,
1058
+ rewrite_ccalls=True,
863
1059
  ) -> None:
864
1060
  """
865
1061
  Simplify the entire function until it reaches a fixed point.
@@ -875,6 +1071,7 @@ class Clinic(Analysis):
875
1071
  narrow_expressions=narrow_expressions and idx == 0,
876
1072
  only_consts=only_consts,
877
1073
  fold_callexprs_into_conditions=fold_callexprs_into_conditions,
1074
+ rewrite_ccalls=rewrite_ccalls,
878
1075
  )
879
1076
  if not simplified:
880
1077
  break
@@ -889,6 +1086,7 @@ class Clinic(Analysis):
889
1086
  narrow_expressions=False,
890
1087
  only_consts=False,
891
1088
  fold_callexprs_into_conditions=False,
1089
+ rewrite_ccalls=True,
892
1090
  ):
893
1091
  """
894
1092
  Simplify the entire function once.
@@ -908,6 +1106,7 @@ class Clinic(Analysis):
908
1106
  only_consts=only_consts,
909
1107
  fold_callexprs_into_conditions=fold_callexprs_into_conditions,
910
1108
  use_callee_saved_regs_at_return=not self._register_save_areas_removed,
1109
+ rewrite_ccalls=rewrite_ccalls,
911
1110
  )
912
1111
  # cache the simplifier's RDA analysis
913
1112
  self.reaching_definitions = simp._reaching_definitions
@@ -923,8 +1122,8 @@ class Clinic(Analysis):
923
1122
  variable_kb=None,
924
1123
  **kwargs,
925
1124
  ):
926
- addr_and_idx_to_blocks: Dict[Tuple[int, Optional[int]], ailment.Block] = {}
927
- addr_to_blocks: Dict[int, Set[ailment.Block]] = defaultdict(set)
1125
+ addr_and_idx_to_blocks: dict[tuple[int, int | None], ailment.Block] = {}
1126
+ addr_to_blocks: dict[int, set[ailment.Block]] = defaultdict(set)
928
1127
 
929
1128
  # update blocks_map to allow node_addr to node lookup
930
1129
  def _updatedict_handler(node):
@@ -963,10 +1162,10 @@ class Clinic(Analysis):
963
1162
  return ail_graph
964
1163
 
965
1164
  @timethis
966
- def _make_argument_list(self) -> List[SimVariable]:
1165
+ def _make_argument_list(self) -> list[SimVariable]:
967
1166
  if self.function.calling_convention is not None and self.function.prototype is not None:
968
- args: List[SimFunctionArgument] = self.function.calling_convention.arg_locs(self.function.prototype)
969
- arg_vars: List[SimVariable] = []
1167
+ args: list[SimFunctionArgument] = self.function.calling_convention.arg_locs(self.function.prototype)
1168
+ arg_vars: list[SimVariable] = []
970
1169
  if args:
971
1170
  arg_names = self.function.prototype.arg_names or [f"a{i}" for i in range(len(args))]
972
1171
  for idx, arg in enumerate(args):
@@ -1041,7 +1240,9 @@ class Clinic(Analysis):
1041
1240
  return simp.result_block
1042
1241
  return None
1043
1242
 
1044
- AILGraphWalker(ail_graph, _handler, replace_nodes=True).walk()
1243
+ # rewriting call-sites at this point, pre-inlining, causes issues with incorrect call signatures
1244
+ if not self._inlining_parents:
1245
+ AILGraphWalker(ail_graph, _handler, replace_nodes=True).walk()
1045
1246
 
1046
1247
  return ail_graph, TempClass.stack_arg_offsets
1047
1248
 
@@ -1050,6 +1251,10 @@ class Clinic(Analysis):
1050
1251
  """
1051
1252
  Work on each return statement and fill in its return expressions.
1052
1253
  """
1254
+ if self._inlining_parents:
1255
+ # for inlining, we want to keep the return statement separate from the return value, so that
1256
+ # the former can be removed while preserving the latter
1257
+ return ail_graph
1053
1258
 
1054
1259
  if self.function.calling_convention is None:
1055
1260
  # unknown calling convention. cannot do much about return expressions.
@@ -1060,7 +1265,7 @@ class Clinic(Analysis):
1060
1265
  return ail_graph
1061
1266
 
1062
1267
  @timethis
1063
- def _make_function_prototype(self, arg_list: List[SimVariable], variable_kb):
1268
+ def _make_function_prototype(self, arg_list: list[SimVariable], variable_kb):
1064
1269
  if self.function.prototype is not None:
1065
1270
  if not self.function.is_prototype_guessed:
1066
1271
  # do not overwrite an existing function prototype
@@ -1567,7 +1772,7 @@ class Clinic(Analysis):
1567
1772
 
1568
1773
  @staticmethod
1569
1774
  def _remove_redundant_jump_blocks(ail_graph):
1570
- def first_conditional_jump(block: ailment.Block) -> Optional[ailment.Stmt.ConditionalJump]:
1775
+ def first_conditional_jump(block: ailment.Block) -> ailment.Stmt.ConditionalJump | None:
1571
1776
  for stmt in block.statements:
1572
1777
  if isinstance(stmt, ailment.Stmt.ConditionalJump):
1573
1778
  return stmt
@@ -1633,7 +1838,7 @@ class Clinic(Analysis):
1633
1838
  expr: ailment.expression.Expression,
1634
1839
  stmt_idx: int,
1635
1840
  stmt: ailment.statement.Statement,
1636
- block: Optional[ailment.Block],
1841
+ block: ailment.Block | None,
1637
1842
  ):
1638
1843
  if expr is None:
1639
1844
  return None
@@ -1645,7 +1850,7 @@ class Clinic(Analysis):
1645
1850
  variables.add(v)
1646
1851
  return ailment.AILBlockWalker._handle_expr(walker, expr_idx, expr, stmt_idx, stmt, block)
1647
1852
 
1648
- def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: Optional[ailment.Block]):
1853
+ def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
1649
1854
  if stmt.variable and stmt.variable in global_vars:
1650
1855
  variables.add(stmt.variable)
1651
1856
  return ailment.AILBlockWalker._handle_Store(walker, stmt_idx, stmt, block)
@@ -1656,17 +1861,17 @@ class Clinic(Analysis):
1656
1861
  return variables
1657
1862
 
1658
1863
  @staticmethod
1659
- def _collect_data_refs(ail_graph) -> Dict[int, List[DataRefDesc]]:
1864
+ def _collect_data_refs(ail_graph) -> dict[int, list[DataRefDesc]]:
1660
1865
  # pylint:disable=unused-argument
1661
1866
  walker = ailment.AILBlockWalker()
1662
- data_refs: Dict[int, List[DataRefDesc]] = defaultdict(list)
1867
+ data_refs: dict[int, list[DataRefDesc]] = defaultdict(list)
1663
1868
 
1664
1869
  def handle_Const(
1665
1870
  expr_idx: int,
1666
1871
  expr: ailment.expression.Const,
1667
1872
  stmt_idx: int,
1668
1873
  stmt: ailment.statement.Statement,
1669
- block: Optional[ailment.Block],
1874
+ block: ailment.Block | None,
1670
1875
  ):
1671
1876
  if isinstance(expr.value, int) and hasattr(expr, "ins_addr"):
1672
1877
  data_refs[block.addr].append(
@@ -1684,7 +1889,7 @@ class Clinic(Analysis):
1684
1889
  expr: ailment.expression.Load,
1685
1890
  stmt_idx: int,
1686
1891
  stmt: ailment.statement.Statement,
1687
- block: Optional[ailment.Block],
1892
+ block: ailment.Block | None,
1688
1893
  ):
1689
1894
  if isinstance(expr.addr, ailment.expression.Const):
1690
1895
  addr = expr.addr
@@ -1714,7 +1919,7 @@ class Clinic(Analysis):
1714
1919
 
1715
1920
  return ailment.AILBlockWalker._handle_Load(walker, expr_idx, expr, stmt_idx, stmt, block)
1716
1921
 
1717
- def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: Optional[ailment.Block]):
1922
+ def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
1718
1923
  if isinstance(stmt.addr, ailment.expression.Const):
1719
1924
  addr = stmt.addr
1720
1925
  if isinstance(addr.value, int) and hasattr(addr, "ins_addr"):
@@ -1760,7 +1965,7 @@ class Clinic(Analysis):
1760
1965
  op_type = kwargs.pop("op_type")
1761
1966
  return isinstance(stmt, ailment.Stmt.Call) and op_type == OP_BEFORE
1762
1967
 
1763
- def parse_variable_addr(self, addr: ailment.Expr.Expression) -> Optional[Tuple[Any, Any]]:
1968
+ def parse_variable_addr(self, addr: ailment.Expr.Expression) -> tuple[Any, Any] | None:
1764
1969
  if isinstance(addr, ailment.Expr.Const):
1765
1970
  return addr, 0
1766
1971
  if isinstance(addr, ailment.Expr.BinaryOp):
@@ -1,5 +1,6 @@
1
1
  from collections import defaultdict, OrderedDict
2
- from typing import Generator, Dict, Any, Optional, Set, List
2
+ from typing import Any
3
+ from collections.abc import Generator
3
4
  import operator
4
5
  import logging
5
6
 
@@ -124,6 +125,7 @@ _ail2claripy_op_mapping = {
124
125
  "SCarry": lambda expr, _, m: _dummy_bvs(expr, m),
125
126
  "SBorrow": lambda expr, _, m: _dummy_bvs(expr, m),
126
127
  "ExpCmpNE": lambda expr, _, m: _dummy_bools(expr, m),
128
+ "CmpORD": lambda expr, _, m: _dummy_bvs(expr, m), # in case CmpORDRewriter fails
127
129
  }
128
130
 
129
131
  #
@@ -138,8 +140,8 @@ class ConditionProcessor:
138
140
 
139
141
  def __init__(self, arch, condition_mapping=None):
140
142
  self.arch = arch
141
- self._condition_mapping: Dict[str, Any] = {} if condition_mapping is None else condition_mapping
142
- self.jump_table_conds: Dict[int, Set] = defaultdict(set)
143
+ self._condition_mapping: dict[str, Any] = {} if condition_mapping is None else condition_mapping
144
+ self.jump_table_conds: dict[int, set] = defaultdict(set)
143
145
  self.edge_conditions = {}
144
146
  self.reaching_conditions = {}
145
147
  self.guarding_conditions = {}
@@ -167,7 +169,7 @@ class ConditionProcessor:
167
169
  predicate = claripy.true
168
170
  return predicate
169
171
 
170
- def recover_edge_conditions(self, region, graph=None) -> Dict:
172
+ def recover_edge_conditions(self, region, graph=None) -> dict:
171
173
  edge_conditions = {}
172
174
  # traverse the graph to recover the condition for each edge
173
175
  graph = graph or region.graph
@@ -181,8 +183,13 @@ class ConditionProcessor:
181
183
  self.edge_conditions = edge_conditions
182
184
 
183
185
  def recover_reaching_conditions(
184
- self, region, graph=None, with_successors=False, case_entry_to_switch_head: Optional[Dict[int, int]] = None
186
+ self, region, graph=None, with_successors=False, case_entry_to_switch_head: dict[int, int] | None = None
185
187
  ):
188
+ """
189
+ Recover the reaching conditions for each block in an acyclic graph. Note that we assume the graph that's passed
190
+ in is acyclic.
191
+ """
192
+
186
193
  def _strictly_postdominates(inv_idoms, node_a, node_b):
187
194
  """
188
195
  Does node A strictly post-dominate node B on the graph?
@@ -457,7 +464,7 @@ class ConditionProcessor:
457
464
  raise NotImplementedError()
458
465
 
459
466
  @classmethod
460
- def get_last_statements(cls, block) -> List[Optional[ailment.Stmt.Statement]]:
467
+ def get_last_statements(cls, block) -> list[ailment.Stmt.Statement | None]:
461
468
  if type(block) is SequenceNode:
462
469
  for last_node in reversed(block.nodes):
463
470
  try:
@@ -837,7 +844,7 @@ class ConditionProcessor:
837
844
  return symbol
838
845
 
839
846
  @staticmethod
840
- def sympy_expr_to_claripy_ast(expr, memo: Dict):
847
+ def sympy_expr_to_claripy_ast(expr, memo: dict):
841
848
  if expr.is_Symbol:
842
849
  return memo[expr]
843
850
  if isinstance(expr, sympy.Or):
@@ -1134,7 +1141,7 @@ class ConditionProcessor:
1134
1141
 
1135
1142
  @staticmethod
1136
1143
  def _remove_crossing_edges_between_cases(
1137
- graph: networkx.DiGraph, case_entry_to_switch_head: Dict[int, int]
1144
+ graph: networkx.DiGraph, case_entry_to_switch_head: dict[int, int]
1138
1145
  ) -> networkx.DiGraph:
1139
1146
  starting_nodes = {node for node in graph if node.addr in case_entry_to_switch_head}
1140
1147
  if not starting_nodes:
@@ -1,4 +1,4 @@
1
- from typing import Optional, Set, Dict, Tuple, Any, TYPE_CHECKING
1
+ from typing import Any, TYPE_CHECKING
2
2
 
3
3
  from .clinic import Clinic
4
4
  from .structured_codegen import BaseStructuredCodeGenerator
@@ -25,13 +25,13 @@ class DecompilationCache:
25
25
 
26
26
  def __init__(self, addr):
27
27
  self.addr = addr
28
- self.type_constraints: Optional[Set] = None
28
+ self.type_constraints: set | None = None
29
29
  self.func_typevar = None
30
- self.var_to_typevar: Optional[Dict] = None
31
- self.codegen: Optional[BaseStructuredCodeGenerator] = None
32
- self.clinic: Optional[Clinic] = None
33
- self.ite_exprs: Optional[Set[Tuple[int, Any]]] = None
34
- self.binop_operators: Optional[Dict["OpDescriptor", str]] = None
30
+ self.var_to_typevar: dict | None = None
31
+ self.codegen: BaseStructuredCodeGenerator | None = None
32
+ self.clinic: Clinic | None = None
33
+ self.ite_exprs: set[tuple[int, Any]] | None = None
34
+ self.binop_operators: dict["OpDescriptor", str] | None = None
35
35
 
36
36
  @property
37
37
  def local_types(self):