angr 9.2.131__py3-none-win_amd64.whl → 9.2.133__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.

Files changed (265) hide show
  1. angr/__init__.py +128 -128
  2. angr/analyses/__init__.py +38 -38
  3. angr/analyses/analysis.py +6 -2
  4. angr/analyses/backward_slice.py +3 -4
  5. angr/analyses/binary_optimizer.py +5 -12
  6. angr/analyses/bindiff.py +3 -6
  7. angr/analyses/calling_convention.py +3 -4
  8. angr/analyses/cfg/__init__.py +3 -3
  9. angr/analyses/cfg/cfg_base.py +1 -1
  10. angr/analyses/cfg/cfg_emulated.py +5 -5
  11. angr/analyses/cfg/cfg_fast.py +19 -17
  12. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +5 -5
  13. angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +1 -1
  14. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +148 -101
  15. angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +1 -1
  16. angr/analyses/data_dep/__init__.py +4 -4
  17. angr/analyses/datagraph_meta.py +1 -1
  18. angr/analyses/ddg.py +16 -17
  19. angr/analyses/decompiler/__init__.py +12 -12
  20. angr/analyses/decompiler/ail_simplifier.py +24 -12
  21. angr/analyses/decompiler/block_similarity.py +2 -4
  22. angr/analyses/decompiler/block_simplifier.py +10 -21
  23. angr/analyses/decompiler/callsite_maker.py +1 -1
  24. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
  25. angr/analyses/decompiler/clinic.py +122 -41
  26. angr/analyses/decompiler/condition_processor.py +57 -39
  27. angr/analyses/decompiler/counters/__init__.py +3 -3
  28. angr/analyses/decompiler/decompilation_cache.py +7 -7
  29. angr/analyses/decompiler/dephication/__init__.py +1 -1
  30. angr/analyses/decompiler/dephication/graph_rewriting.py +1 -1
  31. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +11 -3
  32. angr/analyses/decompiler/dephication/rewriting_engine.py +169 -45
  33. angr/analyses/decompiler/dephication/seqnode_dephication.py +5 -4
  34. angr/analyses/decompiler/expression_narrower.py +1 -1
  35. angr/analyses/decompiler/graph_region.py +8 -8
  36. angr/analyses/decompiler/optimization_passes/__init__.py +20 -20
  37. angr/analyses/decompiler/optimization_passes/const_derefs.py +1 -0
  38. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +1 -2
  39. angr/analyses/decompiler/optimization_passes/div_simplifier.py +41 -16
  40. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +8 -7
  41. angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +1 -3
  42. angr/analyses/decompiler/optimization_passes/engine_base.py +262 -84
  43. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +175 -39
  44. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +2 -5
  45. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +5 -5
  46. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +12 -3
  47. angr/analyses/decompiler/optimization_passes/optimization_pass.py +42 -19
  48. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +9 -5
  49. angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
  50. angr/analyses/decompiler/peephole_optimizations/base.py +6 -6
  51. angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +2 -0
  52. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
  53. angr/analyses/decompiler/presets/__init__.py +1 -1
  54. angr/analyses/decompiler/region_simplifiers/expr_folding.py +3 -3
  55. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +8 -12
  56. angr/analyses/decompiler/ssailification/rewriting.py +1 -2
  57. angr/analyses/decompiler/ssailification/rewriting_engine.py +139 -56
  58. angr/analyses/decompiler/ssailification/ssailification.py +2 -1
  59. angr/analyses/decompiler/ssailification/traversal.py +4 -6
  60. angr/analyses/decompiler/ssailification/traversal_engine.py +125 -42
  61. angr/analyses/decompiler/structured_codegen/__init__.py +5 -5
  62. angr/analyses/decompiler/structured_codegen/base.py +3 -3
  63. angr/analyses/decompiler/structured_codegen/c.py +39 -40
  64. angr/analyses/decompiler/structuring/__init__.py +3 -3
  65. angr/analyses/decompiler/structuring/phoenix.py +45 -29
  66. angr/analyses/decompiler/structuring/structurer_base.py +2 -2
  67. angr/analyses/decompiler/structuring/structurer_nodes.py +23 -14
  68. angr/analyses/deobfuscator/__init__.py +3 -3
  69. angr/analyses/deobfuscator/irsb_reg_collector.py +29 -60
  70. angr/analyses/deobfuscator/string_obf_finder.py +2 -2
  71. angr/analyses/deobfuscator/string_obf_opt_passes.py +1 -1
  72. angr/analyses/disassembly.py +4 -4
  73. angr/analyses/forward_analysis/__init__.py +1 -1
  74. angr/analyses/forward_analysis/visitors/graph.py +6 -6
  75. angr/analyses/init_finder.py +47 -22
  76. angr/analyses/loop_analysis.py +1 -1
  77. angr/analyses/loopfinder.py +1 -1
  78. angr/analyses/propagator/engine_base.py +21 -14
  79. angr/analyses/propagator/engine_vex.py +149 -179
  80. angr/analyses/propagator/outdated_definition_walker.py +12 -6
  81. angr/analyses/propagator/propagator.py +10 -28
  82. angr/analyses/propagator/top_checker_mixin.py +211 -5
  83. angr/analyses/propagator/vex_vars.py +4 -4
  84. angr/analyses/reaching_definitions/__init__.py +9 -9
  85. angr/analyses/reaching_definitions/call_trace.py +2 -2
  86. angr/analyses/reaching_definitions/dep_graph.py +1 -1
  87. angr/analyses/reaching_definitions/engine_ail.py +304 -329
  88. angr/analyses/reaching_definitions/engine_vex.py +243 -229
  89. angr/analyses/reaching_definitions/function_handler.py +3 -3
  90. angr/analyses/reaching_definitions/function_handler_library/__init__.py +1 -1
  91. angr/analyses/reaching_definitions/rd_state.py +47 -42
  92. angr/analyses/reassembler.py +26 -31
  93. angr/analyses/s_liveness.py +8 -0
  94. angr/analyses/s_propagator.py +18 -3
  95. angr/analyses/s_reaching_definitions/s_rda_view.py +2 -5
  96. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +9 -5
  97. angr/analyses/stack_pointer_tracker.py +4 -4
  98. angr/analyses/typehoon/simple_solver.py +14 -14
  99. angr/analyses/typehoon/translator.py +10 -2
  100. angr/analyses/typehoon/typeconsts.py +11 -3
  101. angr/analyses/typehoon/typevars.py +26 -26
  102. angr/analyses/unpacker/__init__.py +1 -1
  103. angr/analyses/variable_recovery/engine_ail.py +299 -259
  104. angr/analyses/variable_recovery/engine_base.py +138 -121
  105. angr/analyses/variable_recovery/engine_vex.py +175 -185
  106. angr/analyses/variable_recovery/irsb_scanner.py +49 -38
  107. angr/analyses/variable_recovery/variable_recovery.py +28 -5
  108. angr/analyses/variable_recovery/variable_recovery_base.py +33 -34
  109. angr/analyses/variable_recovery/variable_recovery_fast.py +4 -8
  110. angr/analyses/veritesting.py +2 -2
  111. angr/analyses/vfg.py +5 -5
  112. angr/analyses/xrefs.py +46 -19
  113. angr/angrdb/serializers/__init__.py +1 -1
  114. angr/annocfg.py +20 -15
  115. angr/blade.py +2 -2
  116. angr/block.py +20 -25
  117. angr/calling_conventions.py +12 -14
  118. angr/code_location.py +6 -10
  119. angr/codenode.py +3 -3
  120. angr/engines/__init__.py +12 -14
  121. angr/engines/engine.py +24 -61
  122. angr/engines/light/__init__.py +13 -5
  123. angr/engines/light/data.py +1 -1
  124. angr/engines/light/engine.py +1003 -1185
  125. angr/engines/pcode/__init__.py +1 -1
  126. angr/engines/pcode/behavior.py +1 -1
  127. angr/engines/pcode/cc.py +2 -0
  128. angr/engines/pcode/lifter.py +13 -15
  129. angr/engines/soot/expressions/__init__.py +12 -12
  130. angr/engines/soot/statements/__init__.py +6 -6
  131. angr/engines/soot/values/__init__.py +6 -6
  132. angr/engines/soot/values/arrayref.py +2 -2
  133. angr/engines/soot/values/constants.py +1 -1
  134. angr/engines/soot/values/instancefieldref.py +1 -1
  135. angr/engines/soot/values/paramref.py +1 -1
  136. angr/engines/soot/values/staticfieldref.py +1 -1
  137. angr/engines/successors.py +15 -14
  138. angr/engines/vex/__init__.py +5 -5
  139. angr/engines/vex/claripy/ccall.py +2 -2
  140. angr/engines/vex/claripy/datalayer.py +1 -1
  141. angr/engines/vex/claripy/irop.py +19 -19
  142. angr/engines/vex/heavy/__init__.py +2 -2
  143. angr/engines/vex/heavy/actions.py +1 -3
  144. angr/engines/vex/heavy/heavy.py +4 -6
  145. angr/engines/vex/lifter.py +2 -4
  146. angr/engines/vex/light/light.py +0 -2
  147. angr/engines/vex/light/slicing.py +5 -5
  148. angr/exploration_techniques/__init__.py +19 -142
  149. angr/exploration_techniques/base.py +126 -0
  150. angr/exploration_techniques/bucketizer.py +1 -1
  151. angr/exploration_techniques/dfs.py +3 -1
  152. angr/exploration_techniques/director.py +2 -3
  153. angr/exploration_techniques/driller_core.py +1 -1
  154. angr/exploration_techniques/explorer.py +4 -2
  155. angr/exploration_techniques/lengthlimiter.py +2 -1
  156. angr/exploration_techniques/local_loop_seer.py +2 -1
  157. angr/exploration_techniques/loop_seer.py +5 -5
  158. angr/exploration_techniques/manual_mergepoint.py +2 -1
  159. angr/exploration_techniques/memory_watcher.py +3 -1
  160. angr/exploration_techniques/oppologist.py +4 -5
  161. angr/exploration_techniques/slicecutor.py +4 -2
  162. angr/exploration_techniques/spiller.py +1 -1
  163. angr/exploration_techniques/stochastic.py +2 -1
  164. angr/exploration_techniques/stub_stasher.py +2 -1
  165. angr/exploration_techniques/suggestions.py +3 -1
  166. angr/exploration_techniques/symbion.py +3 -1
  167. angr/exploration_techniques/tech_builder.py +2 -1
  168. angr/exploration_techniques/threading.py +2 -11
  169. angr/exploration_techniques/timeout.py +4 -2
  170. angr/exploration_techniques/tracer.py +4 -3
  171. angr/exploration_techniques/unique.py +3 -2
  172. angr/exploration_techniques/veritesting.py +1 -1
  173. angr/factory.py +36 -6
  174. angr/keyed_region.py +4 -4
  175. angr/knowledge_base.py +1 -1
  176. angr/knowledge_plugins/__init__.py +11 -11
  177. angr/knowledge_plugins/cfg/__init__.py +5 -5
  178. angr/knowledge_plugins/cfg/cfg_manager.py +2 -2
  179. angr/knowledge_plugins/cfg/cfg_model.py +8 -8
  180. angr/knowledge_plugins/cfg/cfg_node.py +19 -19
  181. angr/knowledge_plugins/cfg/indirect_jump.py +6 -6
  182. angr/knowledge_plugins/cfg/memory_data.py +5 -7
  183. angr/knowledge_plugins/functions/function.py +48 -52
  184. angr/knowledge_plugins/functions/function_parser.py +4 -4
  185. angr/knowledge_plugins/key_definitions/__init__.py +3 -3
  186. angr/knowledge_plugins/key_definitions/atoms.py +8 -8
  187. angr/knowledge_plugins/key_definitions/definition.py +1 -1
  188. angr/knowledge_plugins/key_definitions/live_definitions.py +30 -27
  189. angr/knowledge_plugins/labels.py +1 -1
  190. angr/knowledge_plugins/propagations/__init__.py +1 -1
  191. angr/knowledge_plugins/propagations/prop_value.py +2 -2
  192. angr/knowledge_plugins/propagations/propagation_model.py +7 -8
  193. angr/knowledge_plugins/propagations/states.py +44 -39
  194. angr/knowledge_plugins/variables/variable_access.py +2 -2
  195. angr/knowledge_plugins/variables/variable_manager.py +24 -10
  196. angr/knowledge_plugins/xrefs/xref.py +5 -8
  197. angr/lib/angr_native.dll +0 -0
  198. angr/misc/__init__.py +4 -4
  199. angr/misc/hookset.py +4 -5
  200. angr/misc/loggers.py +2 -2
  201. angr/misc/telemetry.py +1 -1
  202. angr/procedures/__init__.py +1 -1
  203. angr/procedures/cgc/fdwait.py +2 -2
  204. angr/procedures/definitions/__init__.py +2 -2
  205. angr/procedures/definitions/linux_kernel.py +0 -1
  206. angr/procedures/definitions/parse_syscalls_from_local_system.py +1 -1
  207. angr/procedures/definitions/parse_win32json.py +0 -1
  208. angr/procedures/ntdll/exceptions.py +1 -1
  209. angr/procedures/stubs/format_parser.py +3 -3
  210. angr/procedures/win32/dynamic_loading.py +1 -1
  211. angr/protos/__init__.py +3 -3
  212. angr/sim_manager.py +3 -5
  213. angr/sim_state.py +40 -42
  214. angr/sim_state_options.py +3 -3
  215. angr/sim_type.py +15 -14
  216. angr/sim_variable.py +42 -45
  217. angr/simos/__init__.py +4 -4
  218. angr/simos/cgc.py +1 -1
  219. angr/simos/simos.py +1 -1
  220. angr/simos/userland.py +1 -1
  221. angr/slicer.py +4 -7
  222. angr/state_plugins/__init__.py +34 -34
  223. angr/state_plugins/callstack.py +5 -12
  224. angr/state_plugins/heap/__init__.py +2 -2
  225. angr/state_plugins/heap/heap_brk.py +2 -4
  226. angr/state_plugins/heap/heap_ptmalloc.py +1 -1
  227. angr/state_plugins/jni_references.py +3 -2
  228. angr/state_plugins/scratch.py +1 -1
  229. angr/state_plugins/sim_action.py +1 -4
  230. angr/state_plugins/sim_event.py +1 -1
  231. angr/state_plugins/solver.py +7 -9
  232. angr/state_plugins/uc_manager.py +1 -1
  233. angr/state_plugins/view.py +2 -2
  234. angr/storage/__init__.py +1 -1
  235. angr/storage/file.py +10 -10
  236. angr/storage/memory_mixins/__init__.py +46 -46
  237. angr/storage/memory_mixins/default_filler_mixin.py +1 -3
  238. angr/storage/memory_mixins/javavm_memory_mixin.py +2 -2
  239. angr/storage/memory_mixins/name_resolution_mixin.py +2 -2
  240. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -3
  241. angr/storage/memory_mixins/paged_memory/pages/__init__.py +6 -6
  242. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  243. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +1 -1
  244. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  245. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  246. angr/storage/memory_mixins/regioned_memory/__init__.py +3 -3
  247. angr/storage/memory_mixins/regioned_memory/region_data.py +5 -5
  248. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +7 -9
  249. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +4 -4
  250. angr/storage/memory_object.py +4 -4
  251. angr/utils/__init__.py +3 -3
  252. angr/utils/bits.py +12 -0
  253. angr/utils/dynamic_dictlist.py +1 -1
  254. angr/utils/graph.py +1 -1
  255. angr/utils/orderedset.py +4 -1
  256. angr/utils/segment_list.py +2 -2
  257. angr/utils/ssa/__init__.py +33 -8
  258. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/METADATA +6 -6
  259. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/RECORD +263 -264
  260. angr/analyses/propagator/engine_ail.py +0 -1562
  261. angr/storage/memory_mixins/__init__.pyi +0 -48
  262. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/LICENSE +0 -0
  263. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/WHEEL +0 -0
  264. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/entry_points.txt +0 -0
  265. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/top_level.txt +0 -0
@@ -1,1562 +0,0 @@
1
- # pylint:disable=arguments-differ,arguments-renamed,isinstance-second-argument-not-valid-type
2
- from __future__ import annotations
3
- from typing import TYPE_CHECKING
4
- import logging
5
-
6
- import claripy
7
- from ailment import Stmt, Expr
8
- from unique_log_filter import UniqueLogFilter
9
-
10
- from angr.knowledge_plugins.propagations.prop_value import PropValue, Detail
11
- from angr.knowledge_plugins.key_definitions.atoms import Register
12
-
13
- from angr.code_location import ExternalCodeLocation
14
- from angr.utils.constants import is_alignment_mask
15
- from angr.engines.light import SimEngineLightAILMixin
16
- from angr.sim_variable import SimStackVariable, SimMemoryVariable
17
- from angr.analyses.reaching_definitions.reaching_definitions import OP_BEFORE, OP_AFTER
18
- from .engine_base import SimEnginePropagatorBase
19
-
20
- if TYPE_CHECKING:
21
- from .propagator import PropagatorAILState
22
- from angr.code_location import CodeLocation
23
-
24
- l = logging.getLogger(name=__name__)
25
- l.addFilter(UniqueLogFilter())
26
-
27
-
28
- class SimEnginePropagatorAIL(
29
- SimEngineLightAILMixin,
30
- SimEnginePropagatorBase,
31
- ):
32
- """
33
- The AIl engine for Propagator.
34
- """
35
-
36
- state: PropagatorAILState
37
-
38
- def _is_top(self, expr: claripy.ast.Base | Expr.StackBaseOffset) -> bool:
39
- if isinstance(expr, Expr.StackBaseOffset):
40
- return False
41
- return super()._is_top(expr)
42
-
43
- def extract_offset_to_sp(self, expr: claripy.ast.Base | Expr.StackBaseOffset) -> int | None:
44
- if isinstance(expr, Expr.StackBaseOffset):
45
- return expr.offset
46
- if isinstance(expr, Expr.Expression):
47
- # not supported
48
- return None
49
- return super().extract_offset_to_sp(expr)
50
-
51
- #
52
- # AIL statement handlers
53
- #
54
-
55
- def _handle_Stmt(self, stmt):
56
- # walk stmt.src to find all cases where a register appears above a threshold (so we don't incorrectly
57
- # replace the first one)
58
- from angr.analyses.decompiler.counters.expression_counters import (
59
- RegisterExpressionCounter,
60
- OperatorCounter,
61
- ) # pylint:disable=wrong-import-position
62
-
63
- # special case: if shift-right appears in stmt.src, we allow replacement of all registers even if they appear
64
- # multiple times in this statement. this is to allow the optimization of modulos and divisions later.
65
- octr = OperatorCounter(["Shr", "Sar"], stmt)
66
- if octr.count >= 1:
67
- pass
68
- else:
69
- if isinstance(stmt, Stmt.Assignment):
70
- ctr = RegisterExpressionCounter(stmt.src)
71
- else:
72
- ctr = RegisterExpressionCounter(stmt)
73
- self._multi_occurrence_registers = {key for key, count in ctr.counts.items() if count > 1}
74
-
75
- super()._handle_Stmt(stmt)
76
-
77
- self._multi_occurrence_registers = None
78
-
79
- def _ail_handle_Assignment(self, stmt):
80
- """
81
-
82
- :param Stmt.Assignment stmt:
83
- :return:
84
- """
85
-
86
- src = self._expr(stmt.src)
87
- dst = stmt.dst
88
-
89
- if type(dst) is Expr.Tmp:
90
- self.state.store_temp(dst.tmp_idx, src)
91
- self.state.temp_expressions[dst.tmp_idx] = stmt.src
92
-
93
- elif type(dst) is Expr.Register:
94
- codeloc = self._codeloc()
95
-
96
- if src.needs_details:
97
- # provide details
98
- src = src.with_details(dst.size, dst, self._codeloc())
99
-
100
- # do not store tmps into register
101
- if any(self.has_tmpexpr(expr) for expr in src.all_exprs()):
102
- src = PropValue(src.value, offset_and_details={0: Detail(src.value.size() // 8, dst, None)})
103
- self.state.store_register(dst, src)
104
-
105
- if (
106
- isinstance(stmt.src, (Expr.Register, Stmt.Call))
107
- or isinstance(stmt.src, (Expr.Convert))
108
- and isinstance(stmt.src.operand, Stmt.Call)
109
- ):
110
- # set equivalence
111
- self.state.add_equivalence(codeloc, dst, stmt.src)
112
-
113
- if src.one_expr is not None:
114
- self.state.register_expressions[(dst.reg_offset, dst.size)] = dst, src.one_expr, codeloc
115
- else:
116
- self.state.register_expressions[(dst.reg_offset, dst.size)] = dst, stmt.src, codeloc
117
-
118
- if dst.reg_offset == self.arch.sp_offset:
119
- self.state._sp_adjusted = True
120
- else:
121
- l.warning("Unsupported type of Assignment dst %s.", type(dst).__name__)
122
-
123
- def _ail_handle_Store(self, stmt: Stmt.Store):
124
- self.state: PropagatorAILState
125
-
126
- addr = self._expr(stmt.addr)
127
- data = self._expr(stmt.data)
128
-
129
- # is it accessing the stack?
130
- sp_offset = self.extract_offset_to_sp(addr.one_expr) if addr.one_expr is not None else None
131
- if sp_offset is not None:
132
- if isinstance(data.one_expr, Expr.StackBaseOffset):
133
- # convert it to a BV
134
- expr = data.one_expr
135
- data_v = self.sp_offset(stmt.addr.bits, data.one_expr.offset)
136
- size = data_v.size() // self.arch.byte_width
137
- to_store = PropValue.from_value_and_details(data_v, size, expr, self._codeloc())
138
- elif isinstance(data.value, claripy.ast.BV):
139
- expr = data.one_expr if data.one_expr is not None else stmt.data
140
- data_v = data.value
141
- size = data_v.size() // self.arch.byte_width
142
- to_store = PropValue.from_value_and_details(data_v, size, expr, self._codeloc())
143
- else:
144
- expr = data.one_expr
145
- size = stmt.size
146
- to_store = data.with_details(
147
- stmt.size, data.one_expr if data.one_expr is not None else stmt.data, self._codeloc()
148
- )
149
-
150
- # ensure there isn't a Tmp variable in the data
151
- if expr is None or not self.has_tmpexpr(expr):
152
- # Storing data to a stack variable
153
- self.state.store_stack_variable(sp_offset, to_store, endness=stmt.endness)
154
-
155
- # set equivalence
156
- var = SimStackVariable(sp_offset, size)
157
- self.state.add_equivalence(self._codeloc(), var, stmt.data)
158
-
159
- else:
160
- addr_concrete = addr.one_expr
161
- if addr_concrete is None:
162
- # it can be a potential stack store with a variable offset
163
- self.state.last_stack_store = (self.block.addr, self.stmt_idx, stmt)
164
- else:
165
- self.state.global_stores.append((self.block.addr, self.stmt_idx, addr_concrete, stmt))
166
- if isinstance(addr_concrete, Expr.Const) and isinstance(stmt.size, int):
167
- # set equivalence
168
- var = SimMemoryVariable(addr_concrete.value, stmt.size)
169
- self.state.add_equivalence(self._codeloc(), var, stmt.data)
170
-
171
- def _ail_handle_Jump(self, stmt):
172
- target = self._expr(stmt.target)
173
- if target is None or target.one_expr == stmt.target:
174
- return
175
-
176
- target_oneexpr = target.one_expr
177
- if target_oneexpr is not None and isinstance(target_oneexpr, Expr.Const):
178
- new_jump_stmt = Stmt.Jump(stmt.idx, target.one_expr, **stmt.tags)
179
- self.state.add_replacement(
180
- self._codeloc(),
181
- stmt,
182
- new_jump_stmt,
183
- )
184
-
185
- def _ail_handle_Call(self, expr_stmt: Stmt.Call):
186
- if isinstance(expr_stmt.target, Expr.Expression):
187
- _ = self._expr(expr_stmt.target)
188
-
189
- if expr_stmt.args:
190
- for arg in expr_stmt.args:
191
- _ = self._expr(arg)
192
-
193
- if expr_stmt.ret_expr is not None:
194
- if isinstance(expr_stmt.ret_expr, Expr.Register):
195
- # it has a return expression. awesome - treat it as an assignment
196
-
197
- # assume the return value always uses a full-width register
198
- # FIXME: Expose it as a configuration option
199
- return_value_use_full_width_reg = True
200
- if return_value_use_full_width_reg:
201
- v = PropValue.from_value_and_details(
202
- self.state.top(self.arch.bits), self.arch.bytes, expr_stmt.ret_expr, self._codeloc()
203
- )
204
- self.state.store_register(
205
- Expr.Register(
206
- None,
207
- expr_stmt.ret_expr.variable,
208
- expr_stmt.ret_expr.reg_offset,
209
- self.arch.bits,
210
- reg_name=self.arch.translate_register_name(
211
- expr_stmt.ret_expr.reg_offset, size=self.arch.bits
212
- ),
213
- ),
214
- v,
215
- )
216
- else:
217
- v = PropValue.from_value_and_details(
218
- self.state.top(expr_stmt.ret_expr.size * self.arch.byte_width),
219
- expr_stmt.ret_expr.size,
220
- expr_stmt.ret_expr,
221
- self._codeloc(),
222
- )
223
- self.state.store_register(expr_stmt.ret_expr, v)
224
- # set equivalence
225
- self.state.add_equivalence(self._codeloc(), expr_stmt.ret_expr, expr_stmt)
226
- else:
227
- l.warning("Unsupported ret_expr type %s.", expr_stmt.ret_expr.__class__)
228
-
229
- if self.state._sp_adjusted and self.arch.call_pushes_ret:
230
- # stack pointers still exist in the block. so we must emulate the return of the call
231
- sp_reg = Expr.Register(None, None, self.arch.sp_offset, self.arch.bits)
232
- sp_value = self.state.load_register(sp_reg)
233
- if sp_value is not None and 0 in sp_value.offset_and_details and len(sp_value.offset_and_details) == 1:
234
- sp_expr = sp_value.offset_and_details[0].expr
235
- if sp_expr is not None:
236
- if isinstance(sp_expr, Expr.StackBaseOffset):
237
- sp_expr_new = sp_expr.copy()
238
- sp_expr_new.offset += self.arch.bytes
239
- else:
240
- sp_expr_new = Expr.BinaryOp(
241
- None, "Add", [sp_expr, Expr.Const(None, None, self.arch.bytes, sp_expr.bits)], False
242
- )
243
- sp_value_new = PropValue(
244
- sp_value.value + self.arch.bytes,
245
- offset_and_details={
246
- 0: Detail(
247
- sp_value.offset_and_details[0].size,
248
- sp_expr_new,
249
- self._codeloc(),
250
- )
251
- },
252
- )
253
- self.state.store_register(sp_reg, sp_value_new)
254
-
255
- def _ail_handle_ConditionalJump(self, stmt):
256
- condition = self._expr(stmt.condition)
257
- true_target = self._expr(stmt.true_target) if stmt.true_target is not None else None
258
- _ = self._expr(stmt.false_target) if stmt.false_target is not None else None
259
-
260
- # parse the condition to set initial values for true/false branches
261
- if condition is not None and isinstance(true_target.one_expr, Expr.Const):
262
- cond_expr = condition.one_expr
263
- if (
264
- isinstance(cond_expr, Expr.BinaryOp)
265
- and cond_expr.op == "CmpEQ"
266
- and isinstance(cond_expr.operands[1], Expr.Const)
267
- ):
268
- # is there a register that's equivalent to the variable?
269
- for _, (reg_atom, reg_expr, _) in self.state.register_expressions.items():
270
- if cond_expr.operands[0] == reg_expr:
271
- # found it!
272
- key = self.block.addr, true_target.one_expr.value
273
- self.state.block_initial_reg_values[key].append(
274
- (
275
- reg_atom,
276
- cond_expr.operands[1],
277
- )
278
- )
279
-
280
- def _ail_handle_Return(self, stmt: Stmt.Return):
281
- if stmt.ret_exprs:
282
- for ret_expr in stmt.ret_exprs:
283
- self._expr(ret_expr)
284
-
285
- #
286
- # AIL expression handlers
287
- #
288
-
289
- # this method exists so that I can annotate the return type
290
- def _expr(self, expr) -> PropValue | None: # pylint:disable=useless-super-delegation
291
- return super()._expr(expr)
292
-
293
- def _ail_handle_Tmp(self, expr: Expr.Tmp) -> PropValue:
294
- tmp = self.state.load_tmp(expr.tmp_idx)
295
-
296
- if tmp is not None:
297
- # very first step - if we can get rid of this tmp and replace it with another, we should
298
- if expr.tmp_idx in self.state.temp_expressions:
299
- tmp_expr = self.state.temp_expressions[expr.tmp_idx]
300
- for _, (reg_atom, reg_expr, def_at) in self.state.register_expressions.items():
301
- if reg_expr.likes(tmp_expr):
302
- # make sure the register still holds the same value
303
- current_reg_value = self.state.load_register(reg_atom)
304
- if current_reg_value is not None and 0 in current_reg_value.offset_and_details:
305
- detail = current_reg_value.offset_and_details[0]
306
- if detail.def_at == def_at:
307
- outdated = False
308
- outdated_, has_avoid_ = self.is_using_outdated_def(
309
- detail.expr, detail.def_at, self._codeloc(), avoid=expr
310
- )
311
- if outdated_ or has_avoid_:
312
- outdated = True
313
- if not outdated:
314
- l.debug("Add a replacement: %s with %s", expr, reg_atom)
315
- self.state.add_replacement(self._codeloc(), expr, reg_atom)
316
- top = self.state.top(expr.size * self.arch.byte_width)
317
- return PropValue.from_value_and_details(top, expr.size, expr, self._codeloc())
318
-
319
- # check if this new_expr uses any expression that has been overwritten
320
- all_subexprs = list(tmp.all_exprs())
321
- outdated = False
322
- offset_and_details = tmp.offset_and_details or {}
323
- for detail in offset_and_details.values():
324
- if detail.expr is None:
325
- continue
326
- outdated_, has_avoid_ = self.is_using_outdated_def(
327
- detail.expr, detail.def_at, self._codeloc(), avoid=expr
328
- )
329
- if outdated_ or has_avoid_:
330
- outdated = True
331
- break
332
-
333
- if not offset_and_details:
334
- l.warning("Tmp expression has no details or offsets")
335
- return tmp
336
-
337
- if None in all_subexprs or outdated:
338
- top = self.state.top(expr.size * self.arch.byte_width)
339
- self.state.add_replacement(self._codeloc(), expr, top)
340
- return PropValue.from_value_and_details(top, expr.size, expr, self._codeloc())
341
-
342
- if len(all_subexprs) == 1 and 0 in tmp.offset_and_details and tmp.offset_and_details[0].size == expr.size:
343
- subexpr = all_subexprs[0]
344
- l.debug("Add a replacement: %s with %s", expr, subexpr)
345
- self.state.add_replacement(self._codeloc(), expr, subexpr)
346
- elif tmp.offset_and_details and 0 in tmp.offset_and_details:
347
- non_zero_subexprs = list(tmp.non_zero_exprs())
348
- if len(non_zero_subexprs) == 1 and non_zero_subexprs[0] is tmp.offset_and_details[0].expr:
349
- # we will use the zero-extended version as the replacement
350
- subexpr = non_zero_subexprs[0]
351
- subexpr = PropValue.extend_ail_expression(expr.bits - subexpr.bits, subexpr)
352
- l.debug("Add a replacement: %s with %s", expr, subexpr)
353
- self.state.add_replacement(self._codeloc(), expr, subexpr)
354
- return tmp
355
-
356
- if not self._propagate_tmps:
357
- # we should not propagate any tmps. as a result, we return None for reading attempts to a tmp.
358
- return PropValue(self.state.top(expr.size * self.arch.byte_width))
359
-
360
- return PropValue(self.state.top(expr.size * self.arch.byte_width))
361
-
362
- def _ail_handle_Register(self, expr: Expr.Register) -> PropValue | None:
363
- self.state: PropagatorAILState
364
-
365
- # Special handling for SP and BP
366
- if self._stack_pointer_tracker is not None:
367
- if expr.reg_offset == self.arch.sp_offset:
368
- sb_offset = self._stack_pointer_tracker.offset_before(self.ins_addr, self.arch.sp_offset)
369
- if sb_offset is not None:
370
- new_expr = Expr.StackBaseOffset(None, self.arch.bits, sb_offset)
371
- self.state.add_replacement(self._codeloc(), expr, new_expr, bp_as_gpr=self.bp_as_gpr)
372
- return PropValue.from_value_and_details(
373
- self.sp_offset(expr.bits, sb_offset), expr.size, new_expr, self._codeloc()
374
- )
375
- elif expr.reg_offset == self.arch.bp_offset and not self.bp_as_gpr:
376
- sb_offset = self._stack_pointer_tracker.offset_before(self.ins_addr, self.arch.bp_offset)
377
- if sb_offset is not None:
378
- new_expr = Expr.StackBaseOffset(None, self.arch.bits, sb_offset)
379
- self.state.add_replacement(self._codeloc(), expr, new_expr, bp_as_gpr=self.bp_as_gpr)
380
- return PropValue.from_value_and_details(
381
- self.sp_offset(expr.bits, sb_offset), expr.size, new_expr, self._codeloc()
382
- )
383
-
384
- # determine if we should skip replacing the current register
385
- if self._multi_occurrence_registers and (expr.reg_offset, expr.size) in self._multi_occurrence_registers:
386
- # don't replace this register
387
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
388
-
389
- def _test_concatenation(pv: PropValue):
390
- if pv.offset_and_details is not None and len(pv.offset_and_details) == 2 and 0 in pv.offset_and_details:
391
- lo_value = pv.offset_and_details[0]
392
- hi_offset = next(iter(k for k in pv.offset_and_details if k != 0))
393
- hi_value = pv.offset_and_details[hi_offset]
394
- if lo_value.def_at == hi_value.def_at or isinstance(hi_value.expr, Expr.Const):
395
- # it's the same value or the high-end extension is a pure constant. we can apply concatenation here
396
- if isinstance(hi_value.expr, Expr.Const) and hi_value.expr.value == 0:
397
- # it's probably an up-cast
398
- mappings = {
399
- # (lo_value.size, hi_value.size): (from_bits, to_bits)
400
- (1, 1): (8, 16), # char to short
401
- (1, 3): (8, 32), # char to int
402
- (1, 7): (8, 64), # char to int64
403
- (2, 2): (16, 32), # short to int
404
- (2, 6): (16, 64), # short to int64
405
- (4, 4): (32, 64), # int to int64
406
- }
407
- key = (lo_value.size, hi_value.size)
408
- if key in mappings:
409
- from_bits, to_bits = mappings[key]
410
- result_expr = Expr.Convert(None, from_bits, to_bits, False, lo_value.expr, **expr.tags)
411
- return True, result_expr
412
- result_expr = Expr.BinaryOp(None, "Concat", [hi_value.expr, lo_value.expr], False)
413
- return True, result_expr
414
- return False, None
415
-
416
- new_expr = self.state.load_register(expr)
417
-
418
- # where was this register defined?
419
- reg_defat = None
420
- if self._reaching_definitions is not None:
421
- codeloc = self._codeloc()
422
- reg_defat_defs = self._reaching_definitions.get_defs(
423
- Register(expr.reg_offset, expr.size), codeloc, OP_BEFORE
424
- )
425
- reg_defat_codelocs = {reg_def.codeloc for reg_def in reg_defat_defs}
426
- if len(reg_defat_codelocs) == 1:
427
- reg_defat = next(iter(reg_defat_codelocs))
428
- if reg_defat.stmt_idx is None:
429
- # the observation point is in a callee function
430
- reg_defat = None
431
- if isinstance(reg_defat, ExternalCodeLocation):
432
- reg_defat = None
433
-
434
- stmt_to_remove = None
435
- if new_expr is not None:
436
- has_avoid_ = False
437
-
438
- # check if this new_expr uses any expression that has been overwritten
439
- replaced = False
440
- outdated = False
441
- all_subexprs = list(new_expr.all_exprs())
442
- for _, detail in new_expr.offset_and_details.items():
443
- if detail.expr is None:
444
- break
445
- outdated_, has_avoid_ = self.is_using_outdated_def(
446
- detail.expr,
447
- reg_defat if reg_defat is not None else detail.def_at,
448
- self._codeloc(),
449
- avoid=expr,
450
- )
451
- if outdated_ or has_avoid_:
452
- outdated = True
453
- break
454
-
455
- if (
456
- all_subexprs
457
- and None not in all_subexprs
458
- and len(all_subexprs) == 1
459
- and has_avoid_
460
- and self._reaching_definitions is not None
461
- ) and (
462
- # special case:
463
- #
464
- # 1 | ecx_1 = ecx_0 + ebx
465
- # 2 | eax = ecx_1 + 2
466
- #
467
- # since ecx_0 is dead after statement 1, we can always propagate ecx_1 as long as we guarantee the
468
- # removal of statement 1 in a later pass, immediately after we perform replacements.
469
- self._multi_occurrence_registers is None
470
- or (expr.reg_offset, expr.size) not in self._multi_occurrence_registers
471
- ):
472
- reg_defs = self._reaching_definitions.get_defs(
473
- Register(expr.reg_offset, expr.size), self._codeloc(), OP_BEFORE
474
- )
475
- if len(reg_defs) == 1:
476
- reg_def = next(iter(reg_defs))
477
- # is it only used once?
478
- reg_uses = self._reaching_definitions.all_uses.get_uses(reg_def)
479
- if (
480
- len(reg_uses) == 1
481
- # is the definition location an assignment statement?
482
- and reg_def.codeloc.block_addr == self.block.addr
483
- and reg_def.codeloc.stmt_idx == self.stmt_idx - 1
484
- ):
485
- stmt = self.block.statements[reg_def.codeloc.stmt_idx]
486
- if (
487
- isinstance(stmt, Stmt.Assignment)
488
- and isinstance(stmt.dst, Expr.Register)
489
- and stmt.dst.size == expr.size
490
- and all_subexprs[0].likes(stmt.src)
491
- and not self.state.has_replacements_at(reg_def.codeloc)
492
- ):
493
- # ok we are getting rid of the original statement
494
- outdated = False
495
- stmt_to_remove = reg_def.codeloc
496
-
497
- if all_subexprs and None not in all_subexprs and not outdated:
498
- if len(all_subexprs) == 1:
499
- # trivial case
500
- subexpr = all_subexprs[0]
501
- if subexpr.size == expr.size:
502
- force_replace = self.should_force_replace(self.block.statements[self.stmt_idx], subexpr)
503
- l.debug("Try to add a replacement: %s with %s", expr, subexpr)
504
- replaced = self.state.add_replacement(
505
- self._codeloc(),
506
- expr,
507
- subexpr,
508
- force_replace=force_replace,
509
- stmt_to_remove=stmt_to_remove,
510
- bp_as_gpr=self.bp_as_gpr,
511
- )
512
- else:
513
- is_concatenation, result_expr = _test_concatenation(new_expr)
514
- if is_concatenation:
515
- l.debug("Try to add a replacement: %s with %s", expr, result_expr)
516
- force_replace = self.should_force_replace(self.block.statements[self.stmt_idx], result_expr)
517
- replaced = self.state.add_replacement(
518
- self._codeloc(),
519
- expr,
520
- result_expr,
521
- force_replace=force_replace,
522
- stmt_to_remove=stmt_to_remove,
523
- bp_as_gpr=self.bp_as_gpr,
524
- )
525
- elif (
526
- all_subexprs
527
- and None not in all_subexprs
528
- and len(all_subexprs) == 1
529
- and self._reaching_definitions is not None
530
- ):
531
- # if the expression has been replaced before, we should remove previous replacements
532
- reg_defs = self._reaching_definitions.get_defs(
533
- Register(expr.reg_offset, expr.size), self._codeloc(), OP_BEFORE
534
- )
535
- reg_def = next(iter(reg_defs)) if len(reg_defs) == 1 else None
536
- updated_codelocs = self.state.revert_past_replacements(
537
- all_subexprs[0], to_replace=expr, to_replace_def=reg_def
538
- )
539
- # scan through the code locations and recursively remove assignment replacements
540
- while updated_codelocs:
541
- new_updated_codelocs = set()
542
- for u_codeloc in updated_codelocs:
543
- if (
544
- u_codeloc.block_addr == self.block.addr
545
- and isinstance(self.block.statements[u_codeloc.stmt_idx], Stmt.Assignment)
546
- and isinstance(self.block.statements[u_codeloc.stmt_idx].dst, Expr.Register)
547
- ):
548
- dst_reg = self.block.statements[u_codeloc.stmt_idx].dst
549
- # where is this assignment used?
550
- reg_defs = self._reaching_definitions.get_defs(
551
- Register(dst_reg.reg_offset, dst_reg.size), u_codeloc, OP_AFTER
552
- )
553
- if len(reg_defs) == 1:
554
- reg_def = next(iter(reg_defs))
555
- uses = self._reaching_definitions.all_uses.get_uses(reg_def)
556
- for used_codeloc in uses:
557
- if used_codeloc in self.state._replacements:
558
- for to_replace, replace_by in list(
559
- self.state._replacements[used_codeloc].items()
560
- ):
561
- if isinstance(replace_by, dict):
562
- replace_by = replace_by["expr"]
563
- if not self.state.is_top(replace_by) and to_replace.likes(dst_reg):
564
- del self.state._replacements[used_codeloc][to_replace]
565
- new_updated_codelocs.add(used_codeloc)
566
- updated_codelocs = new_updated_codelocs
567
-
568
- if not replaced:
569
- l.debug("Add a replacement: %s with TOP", expr)
570
- self.state.add_replacement(self._codeloc(), expr, self.state.top(expr.bits), bp_as_gpr=self.bp_as_gpr)
571
- else:
572
- return new_expr
573
-
574
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
575
-
576
- def _ail_handle_Load(self, expr: Expr.Load) -> PropValue | None:
577
- self.state: PropagatorAILState
578
-
579
- addr = self._expr(expr.addr)
580
-
581
- addr_expr = addr.one_expr
582
- var_defat = None
583
-
584
- if addr_expr is not None:
585
- if isinstance(addr_expr, Expr.StackBaseOffset) and not isinstance(expr.addr, Expr.StackBaseOffset):
586
- l.debug("Add a replacement: %s with %s", expr.addr, addr_expr)
587
- self.state.add_replacement(self._codeloc(), expr.addr, addr_expr)
588
-
589
- sp_offset = self.extract_offset_to_sp(addr_expr)
590
- if sp_offset is not None:
591
- # Stack variable.
592
- var = self.state.load_stack_variable(sp_offset, expr.size, endness=expr.endness)
593
- if var is not None:
594
- var_defat = var.one_defat
595
- # We do not add replacements here since in AIL function and block simplifiers we explicitly forbid
596
- # replacing stack variables, unless this is the parameter of a call (indicated by expr.func_arg is
597
- # True).
598
- if getattr(expr, "func_arg", False) is True or (
599
- self.state._gp is not None
600
- and not self.state.is_top(var.value)
601
- and var.value.concrete
602
- and var.value.concrete_value == self.state._gp
603
- ):
604
- if var.one_expr is not None:
605
- outdated, has_avoid = self.is_using_outdated_def(
606
- var.one_expr, var.one_defat, self._codeloc(), avoid=expr.addr
607
- )
608
- if not (outdated or has_avoid):
609
- l.debug("Add a replacement: %s with %s", expr, var.one_expr)
610
- self.state.add_replacement(self._codeloc(), expr, var.one_expr)
611
- else:
612
- # there isn't a single expression to replace with. remove the old replacement for this
613
- # expression if available.
614
- self.state.add_replacement(self._codeloc(), expr, self.state.top(expr.bits))
615
- if not self.state.is_top(var.value):
616
- return var
617
-
618
- if addr_expr is not None and addr_expr is not expr.addr:
619
- new_expr = Expr.Load(expr.idx, addr_expr, expr.size, expr.endness, **expr.tags)
620
- else:
621
- new_expr = expr
622
- return PropValue.from_value_and_details(
623
- self.state.top(expr.size * self.arch.byte_width),
624
- expr.size,
625
- new_expr,
626
- self._codeloc() if var_defat is None else var_defat,
627
- )
628
-
629
- def _ail_handle_Convert(self, expr: Expr.Convert) -> PropValue:
630
- o_value = self._expr(expr.operand)
631
-
632
- if not (expr.from_type == Expr.Convert.TYPE_INT and expr.to_type == Expr.Convert.TYPE_INT):
633
- # we do not support floating-point conversions
634
- new_value = self.state.top(expr.to_bits)
635
- return PropValue.from_value_and_details(new_value, expr.size, expr, self._codeloc())
636
-
637
- if o_value is None or self.state.is_top(o_value.value):
638
- new_value = self.state.top(expr.to_bits)
639
- else:
640
- if expr.from_bits < expr.to_bits:
641
- if expr.is_signed:
642
- new_value = claripy.SignExt(expr.to_bits - expr.from_bits, o_value.value)
643
- else:
644
- new_value = claripy.ZeroExt(expr.to_bits - expr.from_bits, o_value.value)
645
- elif expr.from_bits > expr.to_bits:
646
- new_value = claripy.Extract(expr.to_bits - 1, 0, o_value.value)
647
- else:
648
- new_value = o_value.value
649
-
650
- o_expr = o_value.one_expr
651
- o_defat = o_value.one_defat
652
- if o_expr is not None:
653
- # easy cases
654
- if type(o_expr) is Expr.Convert:
655
- if expr.from_bits == o_expr.to_bits and expr.to_bits == o_expr.from_bits:
656
- # eliminate the redundant Convert
657
- new_expr = o_expr.operand
658
- else:
659
- new_expr = Expr.Convert(
660
- expr.idx, o_expr.from_bits, expr.to_bits, expr.is_signed, o_expr.operand, **o_expr.tags
661
- )
662
- elif type(o_expr) is Expr.Const:
663
- # do the conversion right away
664
- value = o_expr.value
665
- mask = (2**expr.to_bits) - 1
666
- value &= mask
667
- new_expr = Expr.Const(expr.idx, o_expr.variable, value, expr.to_bits, **expr.tags)
668
- else:
669
- new_expr = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, o_expr, **expr.tags)
670
-
671
- if (
672
- isinstance(new_expr, Expr.Convert)
673
- and not new_expr.is_signed
674
- and new_expr.to_bits > new_expr.from_bits
675
- and new_expr.from_bits % self.arch.byte_width == 0
676
- ):
677
- # special handling for zero-extension: it simplifies the code if we explicitly model zeros
678
- new_size = new_expr.from_bits // self.arch.byte_width
679
- offset_and_details = {
680
- 0: Detail(new_size, new_expr.operand, o_defat),
681
- new_size: Detail(
682
- new_expr.size - new_size,
683
- Expr.Const(expr.idx, None, 0, new_expr.to_bits - new_expr.from_bits, **new_expr.tags),
684
- self._codeloc(),
685
- ),
686
- }
687
- else:
688
- offset_and_details = {0: Detail(expr.size, new_expr, self._codeloc())}
689
-
690
- return PropValue(new_value, offset_and_details=offset_and_details)
691
-
692
- if o_value.offset_and_details:
693
- # hard cases... we will keep certain labels and eliminate other labels
694
- start_offset = 0
695
- end_offset = expr.to_bits // self.arch.byte_width # end_offset is exclusive
696
- offset_and_details = {}
697
- max_offset = max(o_value.offset_and_details.keys())
698
- for offset_, detail_ in o_value.offset_and_details.items():
699
- if offset_ < start_offset < offset_ + detail_.size:
700
- # we start here
701
- off = 0
702
- siz = min(end_offset, offset_ + detail_.size) - start_offset
703
- expr_ = PropValue.extract_ail_expression(
704
- (start_offset - offset_) * self.arch.byte_width, siz * self.arch.byte_width, detail_.expr
705
- )
706
- offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
707
- elif offset_ >= start_offset and offset_ + detail_.size <= end_offset:
708
- # we include the whole thing
709
- off = offset_ - start_offset
710
- siz = detail_.size
711
- if off == max_offset and off + siz < end_offset:
712
- # extend the expr
713
- expr_ = PropValue.extend_ail_expression(
714
- (end_offset - (off + siz)) * self.arch.byte_width, detail_.expr
715
- )
716
- siz = end_offset - off
717
- else:
718
- expr_ = detail_.expr
719
- offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
720
- elif offset_ < end_offset <= offset_ + detail_.size:
721
- # we include all the way until end_offset
722
- if offset_ < start_offset:
723
- off = 0
724
- siz = end_offset - start_offset
725
- else:
726
- off = offset_ - start_offset
727
- siz = end_offset - offset_
728
- expr_ = PropValue.extract_ail_expression(0, siz * self.arch.byte_width, detail_.expr)
729
- offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
730
-
731
- return PropValue(new_value, offset_and_details=offset_and_details)
732
- # it's empty... no expression is available for whatever reason
733
- return PropValue.from_value_and_details(new_value, expr.size, expr, self._codeloc())
734
-
735
- def _ail_handle_Const(self, expr: Expr.Const) -> PropValue:
736
- if isinstance(expr.value, float):
737
- v = claripy.FPV(expr.value, claripy.FSORT_DOUBLE if expr.bits == 64 else claripy.FSORT_FLOAT)
738
- else:
739
- v = claripy.BVV(expr.value, expr.bits)
740
- return PropValue.from_value_and_details(v, expr.size, expr, self._codeloc())
741
-
742
- def _ail_handle_DirtyExpression(self, expr: Expr.DirtyExpression) -> PropValue | None: # pylint:disable=no-self-use
743
- for operand in expr.operands:
744
- _ = self._expr(operand)
745
-
746
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
747
-
748
- def _ail_handle_VEXCCallExpression(
749
- self, expr: Expr.VEXCCallExpression
750
- ) -> PropValue | None: # pylint:disable=no-self-use
751
- for operand in expr.operands:
752
- _ = self._expr(operand)
753
-
754
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
755
-
756
- def _ail_handle_ITE(self, expr: Expr.ITE) -> PropValue | None:
757
- # pylint:disable=unused-variable
758
- self._expr(expr.cond) # cond
759
- self._expr(expr.iftrue) # iftrue
760
- self._expr(expr.iffalse) # iffalse
761
-
762
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
763
-
764
- def _ail_handle_Reinterpret(self, expr: Expr.Reinterpret) -> PropValue | None:
765
- arg = self._expr(expr.operand)
766
-
767
- if self.state.is_top(arg.value):
768
- one_expr = arg.one_expr
769
- if one_expr is not None:
770
- expr = Expr.Reinterpret(
771
- expr.idx, expr.from_bits, expr.from_type, expr.to_bits, expr.to_type, one_expr, **expr.tags
772
- )
773
-
774
- return PropValue.from_value_and_details(arg.value, expr.size, expr, self._codeloc())
775
-
776
- def _ail_handle_CallExpr(self, expr_stmt: Stmt.Call) -> PropValue | None:
777
- if isinstance(expr_stmt.target, Expr.Expression):
778
- _ = self._expr(expr_stmt.target)
779
-
780
- if expr_stmt.args:
781
- for arg in expr_stmt.args:
782
- _ = self._expr(arg)
783
-
784
- # ignore ret_expr
785
- return PropValue.from_value_and_details(
786
- self.state.top(expr_stmt.bits), expr_stmt.size, expr_stmt, self._codeloc()
787
- )
788
-
789
- def _ail_handle_Not(self, expr):
790
- o_value = self._expr(expr.operand)
791
-
792
- value = self.state.top(expr.bits)
793
- if o_value is None:
794
- new_expr = expr
795
- else:
796
- o_expr = o_value.one_expr
797
- new_expr = Expr.UnaryOp(expr.idx, "Not", o_expr if o_expr is not None else expr.operands[0], **expr.tags)
798
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
799
-
800
- def _ail_handle_Neg(self, expr):
801
- o_value = self._expr(expr.operand)
802
-
803
- value = self.state.top(expr.bits)
804
- if o_value is None:
805
- new_expr = expr
806
- else:
807
- o_expr = o_value.one_expr
808
- new_expr = Expr.UnaryOp(expr.idx, "Neg", o_expr if o_expr is not None else expr.operands[0], **expr.tags)
809
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
810
-
811
- def _ail_handle_BitwiseNeg(self, expr):
812
- o_value = self._expr(expr.operand)
813
-
814
- value = self.state.top(expr.bits)
815
- if o_value is None:
816
- new_expr = expr
817
- else:
818
- o_expr = o_value.one_expr
819
- new_expr = Expr.UnaryOp(
820
- expr.idx, "BitwiseNeg", o_expr if o_expr is not None else expr.operands[0], **expr.tags
821
- )
822
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
823
-
824
- def _ail_handle_Cmp(self, expr: Expr.BinaryOp) -> PropValue:
825
- operand_0_value = self._expr(expr.operands[0])
826
- operand_1_value = self._expr(expr.operands[1])
827
-
828
- if operand_0_value is not None and operand_1_value is not None:
829
- operand_0_oneexpr = operand_0_value.one_expr
830
- operand_1_oneexpr = operand_1_value.one_expr
831
- if operand_0_oneexpr is expr.operands[0] and operand_1_oneexpr is expr.operands[1]:
832
- # nothing changed
833
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
834
- operand_0 = operand_0_oneexpr if operand_0_oneexpr is not None else expr.operands[0]
835
- operand_1 = operand_1_oneexpr if operand_1_oneexpr is not None else expr.operands[1]
836
-
837
- new_expr = Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1], expr.signed, **expr.tags)
838
- else:
839
- new_expr = expr
840
-
841
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, new_expr, self._codeloc())
842
-
843
- _ail_handle_CmpF = _ail_handle_Cmp
844
- _ail_handle_CmpLE = _ail_handle_Cmp
845
- _ail_handle_CmpLEs = _ail_handle_Cmp
846
- _ail_handle_CmpLT = _ail_handle_Cmp
847
- _ail_handle_CmpLTs = _ail_handle_Cmp
848
- _ail_handle_CmpGE = _ail_handle_Cmp
849
- _ail_handle_CmpGEs = _ail_handle_Cmp
850
- _ail_handle_CmpGT = _ail_handle_Cmp
851
- _ail_handle_CmpGTs = _ail_handle_Cmp
852
- _ail_handle_CmpEQ = _ail_handle_Cmp
853
- _ail_handle_CmpNE = _ail_handle_Cmp
854
- _ail_handle_CmpORD = _ail_handle_Cmp
855
-
856
- def _ail_handle_Add(self, expr: Expr.BinaryOp) -> PropValue:
857
- o0_value = self._expr(expr.operands[0])
858
- o1_value = self._expr(expr.operands[1])
859
-
860
- if o0_value is None or o1_value is None:
861
- new_expr = expr
862
- value = self.state.top(expr.bits)
863
- else:
864
- if o0_value.value.concrete and o1_value.value.concrete:
865
- value = (o0_value.value + o1_value.value) & ((1 << self.arch.bits) - 1)
866
- else:
867
- value = self.state.top(expr.bits)
868
-
869
- o0_expr = o0_value.one_expr
870
- o1_expr = o1_value.one_expr
871
- if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const):
872
- new_expr = o0_value.one_expr.copy()
873
- new_expr.offset += o1_expr.value
874
- else:
875
- new_expr = Expr.BinaryOp(
876
- expr.idx,
877
- "Add",
878
- [
879
- o0_expr if o0_expr is not None else expr.operands[0],
880
- o1_expr if o1_expr is not None else expr.operands[1],
881
- ],
882
- expr.signed,
883
- floating_point=expr.floating_point,
884
- rounding_mode=expr.rounding_mode,
885
- **expr.tags,
886
- )
887
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
888
-
889
- def _ail_handle_Sub(self, expr: Expr.BinaryOp) -> PropValue:
890
- o0_value = self._expr(expr.operands[0])
891
- o1_value = self._expr(expr.operands[1])
892
-
893
- if o0_value is None or o1_value is None:
894
- new_expr = expr
895
- value = self.state.top(expr.bits)
896
- else:
897
- if o0_value.value.concrete and o1_value.value.concrete:
898
- value = (o0_value.value - o1_value.value) & ((1 << self.arch.bits) - 1)
899
- else:
900
- value = self.state.top(expr.bits)
901
-
902
- o0_expr = o0_value.one_expr
903
- o1_expr = o1_value.one_expr
904
- if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const):
905
- new_expr = o0_value.one_expr.copy()
906
- new_expr.offset -= o1_expr.value
907
- else:
908
- new_expr = Expr.BinaryOp(
909
- expr.idx,
910
- "Sub",
911
- [
912
- o0_expr if o0_expr is not None else expr.operands[0],
913
- o1_expr if o1_expr is not None else expr.operands[1],
914
- ],
915
- expr.signed,
916
- floating_point=expr.floating_point,
917
- rounding_mode=expr.rounding_mode,
918
- **expr.tags,
919
- )
920
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
921
-
922
- def _ail_handle_StackBaseOffset(self, expr: Expr.StackBaseOffset) -> PropValue: # pylint:disable=no-self-use
923
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
924
-
925
- def _ail_handle_And(self, expr: Expr.BinaryOp):
926
- o0_value = self._expr(expr.operands[0])
927
- o1_value = self._expr(expr.operands[1])
928
-
929
- value = self.state.top(expr.bits)
930
- if o0_value is None or o1_value is None:
931
- new_expr = expr
932
- else:
933
- o0_expr = o0_value.one_expr
934
- o1_expr = o1_value.one_expr
935
-
936
- # Special logic for stack pointer alignment
937
- sp_offset = self.extract_offset_to_sp(o0_value.value)
938
- if (
939
- sp_offset is not None
940
- and type(o1_expr) is Expr.Const
941
- and is_alignment_mask(o1_expr.value)
942
- or (
943
- isinstance(o0_expr, Expr.StackBaseOffset)
944
- and type(o1_expr) is Expr.Const
945
- and is_alignment_mask(o1_expr.value)
946
- )
947
- ):
948
- value = o0_value.value
949
- new_expr = o0_expr
950
- else:
951
- value = self.state.top(expr.bits)
952
- new_expr = Expr.BinaryOp(
953
- expr.idx,
954
- "And",
955
- [
956
- o0_expr if o0_expr is not None else expr.operands[0],
957
- o1_expr if o1_expr is not None else expr.operands[1],
958
- ],
959
- expr.signed,
960
- floating_point=expr.floating_point,
961
- rounding_mode=expr.rounding_mode,
962
- **expr.tags,
963
- )
964
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
965
-
966
- def _ail_handle_Or(self, expr: Expr.BinaryOp):
967
- o0_value = self._expr(expr.operands[0])
968
- o1_value = self._expr(expr.operands[1])
969
-
970
- value = self.state.top(expr.bits)
971
- if o0_value is None or o1_value is None:
972
- new_expr = expr
973
- else:
974
- o0_expr = o0_value.one_expr
975
- o1_expr = o1_value.one_expr
976
- new_expr = Expr.BinaryOp(
977
- expr.idx,
978
- "Or",
979
- [
980
- o0_expr if o0_expr is not None else expr.operands[0],
981
- o1_expr if o1_expr is not None else expr.operands[1],
982
- ],
983
- expr.signed,
984
- floating_point=expr.floating_point,
985
- rounding_mode=expr.rounding_mode,
986
- **expr.tags,
987
- )
988
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
989
-
990
- def _ail_handle_Xor(self, expr: Expr.BinaryOp):
991
- o0_value = self._expr(expr.operands[0])
992
- o1_value = self._expr(expr.operands[1])
993
-
994
- value = self.state.top(expr.bits)
995
- if o0_value is None or o1_value is None:
996
- new_expr = expr
997
- else:
998
- o0_expr = o0_value.one_expr
999
- o1_expr = o1_value.one_expr
1000
- new_expr = Expr.BinaryOp(
1001
- expr.idx,
1002
- "Xor",
1003
- [
1004
- o0_expr if o0_expr is not None else expr.operands[0],
1005
- o1_expr if o1_expr is not None else expr.operands[1],
1006
- ],
1007
- expr.signed,
1008
- floating_point=expr.floating_point,
1009
- rounding_mode=expr.rounding_mode,
1010
- **expr.tags,
1011
- )
1012
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1013
-
1014
- def _ail_handle_Shl(self, expr: Expr.BinaryOp):
1015
- o0_value = self._expr(expr.operands[0])
1016
- o1_value = self._expr(expr.operands[1])
1017
-
1018
- value = self.state.top(expr.bits)
1019
- if o0_value is None or o1_value is None:
1020
- new_expr = expr
1021
- else:
1022
- o0_expr = o0_value.one_expr
1023
- o1_expr = o1_value.one_expr
1024
- new_expr = Expr.BinaryOp(
1025
- expr.idx,
1026
- "Shl",
1027
- [
1028
- o0_expr if o0_expr is not None else expr.operands[0],
1029
- o1_expr if o1_expr is not None else expr.operands[1],
1030
- ],
1031
- expr.signed,
1032
- floating_point=expr.floating_point,
1033
- rounding_mode=expr.rounding_mode,
1034
- **expr.tags,
1035
- )
1036
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1037
-
1038
- def _ail_handle_Shr(self, expr: Expr.BinaryOp):
1039
- o0_value = self._expr(expr.operands[0])
1040
- o1_value = self._expr(expr.operands[1])
1041
-
1042
- value = self.state.top(expr.bits)
1043
- if o0_value is None or o1_value is None:
1044
- new_expr = expr
1045
- else:
1046
- o0_expr = o0_value.one_expr
1047
- o1_expr = o1_value.one_expr
1048
- new_expr = Expr.BinaryOp(
1049
- expr.idx,
1050
- "Shr",
1051
- [
1052
- o0_expr if o0_expr is not None else expr.operands[0],
1053
- o1_expr if o1_expr is not None else expr.operands[1],
1054
- ],
1055
- expr.signed,
1056
- floating_point=expr.floating_point,
1057
- rounding_mode=expr.rounding_mode,
1058
- **expr.tags,
1059
- )
1060
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1061
-
1062
- def _ail_handle_Sar(self, expr: Expr.BinaryOp):
1063
- o0_value = self._expr(expr.operands[0])
1064
- o1_value = self._expr(expr.operands[1])
1065
-
1066
- value = self.state.top(expr.bits)
1067
- if o0_value is None or o1_value is None:
1068
- new_expr = expr
1069
- else:
1070
- o0_expr = o0_value.one_expr
1071
- o1_expr = o1_value.one_expr
1072
- new_expr = Expr.BinaryOp(
1073
- expr.idx,
1074
- "Sar",
1075
- [
1076
- o0_expr if o0_expr is not None else expr.operands[0],
1077
- o1_expr if o1_expr is not None else expr.operands[1],
1078
- ],
1079
- expr.signed,
1080
- floating_point=expr.floating_point,
1081
- rounding_mode=expr.rounding_mode,
1082
- **expr.tags,
1083
- )
1084
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1085
-
1086
- def _ail_handle_Rol(self, expr: Expr.BinaryOp):
1087
- o0_value = self._expr(expr.operands[0])
1088
- o1_value = self._expr(expr.operands[1])
1089
-
1090
- value = self.state.top(expr.bits)
1091
- if o0_value is None or o1_value is None:
1092
- new_expr = expr
1093
- else:
1094
- o0_expr = o0_value.one_expr
1095
- o1_expr = o1_value.one_expr
1096
- new_expr = Expr.BinaryOp(
1097
- expr.idx,
1098
- "Rol",
1099
- [
1100
- o0_expr if o0_expr is not None else expr.operands[0],
1101
- o1_expr if o1_expr is not None else expr.operands[1],
1102
- ],
1103
- expr.signed,
1104
- floating_point=expr.floating_point,
1105
- rounding_mode=expr.rounding_mode,
1106
- **expr.tags,
1107
- )
1108
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1109
-
1110
- def _ail_handle_Ror(self, expr: Expr.BinaryOp):
1111
- o0_value = self._expr(expr.operands[0])
1112
- o1_value = self._expr(expr.operands[1])
1113
-
1114
- value = self.state.top(expr.bits)
1115
- if o0_value is None or o1_value is None:
1116
- new_expr = expr
1117
- else:
1118
- o0_expr = o0_value.one_expr
1119
- o1_expr = o1_value.one_expr
1120
- new_expr = Expr.BinaryOp(
1121
- expr.idx,
1122
- "Ror",
1123
- [
1124
- o0_expr if o0_expr is not None else expr.operands[0],
1125
- o1_expr if o1_expr is not None else expr.operands[1],
1126
- ],
1127
- expr.signed,
1128
- floating_point=expr.floating_point,
1129
- rounding_mode=expr.rounding_mode,
1130
- **expr.tags,
1131
- )
1132
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1133
-
1134
- def _ail_handle_Mul(self, expr):
1135
- o0_value = self._expr(expr.operands[0])
1136
- o1_value = self._expr(expr.operands[1])
1137
-
1138
- value = self.state.top(expr.bits)
1139
- if o0_value is None or o1_value is None:
1140
- new_expr = expr
1141
- else:
1142
- o0_expr = o0_value.one_expr
1143
- o1_expr = o1_value.one_expr
1144
- new_expr = Expr.BinaryOp(
1145
- expr.idx,
1146
- "Mul",
1147
- [
1148
- o0_expr if o0_expr is not None else expr.operands[0],
1149
- o1_expr if o1_expr is not None else expr.operands[1],
1150
- ],
1151
- expr.signed,
1152
- floating_point=expr.floating_point,
1153
- rounding_mode=expr.rounding_mode,
1154
- **expr.tags,
1155
- )
1156
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1157
-
1158
- _ail_handle_AddV = _ail_handle_Add
1159
- _ail_handle_MulV = _ail_handle_Mul
1160
-
1161
- def _ail_handle_Mull(self, expr):
1162
- o0_value = self._expr(expr.operands[0])
1163
- o1_value = self._expr(expr.operands[1])
1164
-
1165
- value = self.state.top(expr.bits)
1166
- if o0_value is None or o1_value is None:
1167
- new_expr = expr
1168
- else:
1169
- o0_expr = o0_value.one_expr
1170
- o1_expr = o1_value.one_expr
1171
- new_expr = Expr.BinaryOp(
1172
- expr.idx,
1173
- "Mull",
1174
- [
1175
- o0_expr if o0_expr is not None else expr.operands[0],
1176
- o1_expr if o1_expr is not None else expr.operands[1],
1177
- ],
1178
- expr.signed,
1179
- bits=expr.bits,
1180
- floating_point=expr.floating_point,
1181
- rounding_mode=expr.rounding_mode,
1182
- **expr.tags,
1183
- )
1184
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1185
-
1186
- def _ail_handle_Div(self, expr):
1187
- o0_value = self._expr(expr.operands[0])
1188
- o1_value = self._expr(expr.operands[1])
1189
-
1190
- value = self.state.top(expr.bits)
1191
- if o0_value is None or o1_value is None:
1192
- new_expr = expr
1193
- else:
1194
- o0_expr = o0_value.one_expr
1195
- o1_expr = o1_value.one_expr
1196
- new_expr = Expr.BinaryOp(
1197
- expr.idx,
1198
- "Div",
1199
- [
1200
- o0_expr if o0_expr is not None else expr.operands[0],
1201
- o1_expr if o1_expr is not None else expr.operands[1],
1202
- ],
1203
- expr.signed,
1204
- floating_point=expr.floating_point,
1205
- rounding_mode=expr.rounding_mode,
1206
- **expr.tags,
1207
- )
1208
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1209
-
1210
- def _ail_handle_DivMod(self, expr):
1211
- o0_value = self._expr(expr.operands[0])
1212
- o1_value = self._expr(expr.operands[1])
1213
-
1214
- value = self.state.top(expr.bits)
1215
- if o0_value is None or o1_value is None:
1216
- new_expr = expr
1217
- else:
1218
- o0_expr = o0_value.one_expr
1219
- o1_expr = o1_value.one_expr
1220
- new_expr = Expr.BinaryOp(
1221
- expr.idx,
1222
- "DivMod",
1223
- [
1224
- o0_expr if o0_expr is not None else expr.operands[0],
1225
- o1_expr if o1_expr is not None else expr.operands[1],
1226
- ],
1227
- expr.signed,
1228
- bits=expr.bits,
1229
- floating_point=expr.floating_point,
1230
- rounding_mode=expr.rounding_mode,
1231
- from_bits=expr.from_bits,
1232
- to_bits=expr.to_bits,
1233
- **expr.tags,
1234
- )
1235
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1236
-
1237
- def _ail_handle_Mod(self, expr):
1238
- o0_value = self._expr(expr.operands[0])
1239
- o1_value = self._expr(expr.operands[1])
1240
-
1241
- value = self.state.top(expr.bits)
1242
- if o0_value is None or o1_value is None:
1243
- new_expr = expr
1244
- else:
1245
- o0_expr = o0_value.one_expr
1246
- o1_expr = o1_value.one_expr
1247
- new_expr = Expr.BinaryOp(
1248
- expr.idx,
1249
- "Mod",
1250
- [
1251
- o0_expr if o0_expr is not None else expr.operands[0],
1252
- o1_expr if o1_expr is not None else expr.operands[1],
1253
- ],
1254
- expr.signed,
1255
- floating_point=expr.floating_point,
1256
- rounding_mode=expr.rounding_mode,
1257
- **expr.tags,
1258
- )
1259
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1260
-
1261
- def _ail_handle_LogicalAnd(self, expr: Expr.BinaryOp):
1262
- o0_value = self._expr(expr.operands[0])
1263
- o1_value = self._expr(expr.operands[1])
1264
-
1265
- value = self.state.top(expr.bits)
1266
- if o0_value is None or o1_value is None:
1267
- new_expr = expr
1268
- else:
1269
- o0_expr = o0_value.one_expr
1270
- o1_expr = o1_value.one_expr
1271
-
1272
- value = self.state.top(expr.bits)
1273
- new_expr = Expr.BinaryOp(
1274
- expr.idx,
1275
- "LogicalAnd",
1276
- [
1277
- o0_expr if o0_expr is not None else expr.operands[0],
1278
- o1_expr if o1_expr is not None else expr.operands[1],
1279
- ],
1280
- expr.signed,
1281
- **expr.tags,
1282
- )
1283
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1284
-
1285
- def _ail_handle_LogicalOr(self, expr: Expr.BinaryOp):
1286
- o0_value = self._expr(expr.operands[0])
1287
- o1_value = self._expr(expr.operands[1])
1288
-
1289
- value = self.state.top(expr.bits)
1290
- if o0_value is None or o1_value is None:
1291
- new_expr = expr
1292
- else:
1293
- o0_expr = o0_value.one_expr
1294
- o1_expr = o1_value.one_expr
1295
-
1296
- value = self.state.top(expr.bits)
1297
- new_expr = Expr.BinaryOp(
1298
- expr.idx,
1299
- "LogicalOr",
1300
- [
1301
- o0_expr if o0_expr is not None else expr.operands[0],
1302
- o1_expr if o1_expr is not None else expr.operands[1],
1303
- ],
1304
- expr.signed,
1305
- **expr.tags,
1306
- )
1307
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1308
-
1309
- def _ail_handle_LogicalXor(self, expr: Expr.BinaryOp):
1310
- o0_value = self._expr(expr.operands[0])
1311
- o1_value = self._expr(expr.operands[1])
1312
-
1313
- value = self.state.top(expr.bits)
1314
- if o0_value is None or o1_value is None:
1315
- new_expr = expr
1316
- else:
1317
- o0_expr = o0_value.one_expr
1318
- o1_expr = o1_value.one_expr
1319
-
1320
- value = self.state.top(expr.bits)
1321
- new_expr = Expr.BinaryOp(
1322
- expr.idx,
1323
- "LogicalXor",
1324
- [
1325
- o0_expr if o0_expr is not None else expr.operands[0],
1326
- o1_expr if o1_expr is not None else expr.operands[1],
1327
- ],
1328
- expr.signed,
1329
- **expr.tags,
1330
- )
1331
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1332
-
1333
- def _ail_handle_Carry(self, expr: Expr.BinaryOp):
1334
- o0_value = self._expr(expr.operands[0])
1335
- o1_value = self._expr(expr.operands[1])
1336
-
1337
- value = self.state.top(expr.bits)
1338
- if o0_value is None or o1_value is None:
1339
- new_expr = expr
1340
- else:
1341
- o0_expr = o0_value.one_expr
1342
- o1_expr = o1_value.one_expr
1343
- new_expr = Expr.BinaryOp(
1344
- expr.idx,
1345
- "Carry",
1346
- [
1347
- o0_expr if o0_expr is not None else expr.operands[0],
1348
- o1_expr if o1_expr is not None else expr.operands[1],
1349
- ],
1350
- expr.signed,
1351
- bits=expr.bits,
1352
- floating_point=expr.floating_point,
1353
- rounding_mode=expr.rounding_mode,
1354
- **expr.tags,
1355
- )
1356
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1357
-
1358
- def _ail_handle_SCarry(self, expr: Expr.BinaryOp):
1359
- o0_value = self._expr(expr.operands[0])
1360
- o1_value = self._expr(expr.operands[1])
1361
-
1362
- value = self.state.top(expr.bits)
1363
- if o0_value is None or o1_value is None:
1364
- new_expr = expr
1365
- else:
1366
- o0_expr = o0_value.one_expr
1367
- o1_expr = o1_value.one_expr
1368
- new_expr = Expr.BinaryOp(
1369
- expr.idx,
1370
- "SCarry",
1371
- [
1372
- o0_expr if o0_expr is not None else expr.operands[0],
1373
- o1_expr if o1_expr is not None else expr.operands[1],
1374
- ],
1375
- expr.signed,
1376
- bits=expr.bits,
1377
- floating_point=expr.floating_point,
1378
- rounding_mode=expr.rounding_mode,
1379
- **expr.tags,
1380
- )
1381
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1382
-
1383
- def _ail_handle_SBorrow(self, expr: Expr.BinaryOp):
1384
- o0_value = self._expr(expr.operands[0])
1385
- o1_value = self._expr(expr.operands[1])
1386
-
1387
- value = self.state.top(expr.bits)
1388
- if o0_value is None or o1_value is None:
1389
- new_expr = expr
1390
- else:
1391
- o0_expr = o0_value.one_expr
1392
- o1_expr = o1_value.one_expr
1393
- new_expr = Expr.BinaryOp(
1394
- expr.idx,
1395
- "SBorrow",
1396
- [
1397
- o0_expr if o0_expr is not None else expr.operands[0],
1398
- o1_expr if o1_expr is not None else expr.operands[1],
1399
- ],
1400
- expr.signed,
1401
- bits=expr.bits,
1402
- floating_point=expr.floating_point,
1403
- rounding_mode=expr.rounding_mode,
1404
- **expr.tags,
1405
- )
1406
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1407
-
1408
- def _ail_handle_TernaryOp(self, expr: Expr.TernaryOp):
1409
- o0_value = self._expr(expr.operands[0])
1410
- o1_value = self._expr(expr.operands[1])
1411
- o2_value = self._expr(expr.operands[2])
1412
-
1413
- if o0_value is None or o1_value is None or o2_value is None:
1414
- new_expr = expr
1415
- else:
1416
- o0_expr = o0_value.one_expr
1417
- o1_expr = o1_value.one_expr
1418
- o2_expr = o2_value.one_expr
1419
- new_expr = Expr.TernaryOp(
1420
- expr.idx,
1421
- expr.op,
1422
- [
1423
- o0_expr if o0_expr is not None else expr.operands[0],
1424
- o1_expr if o1_expr is not None else expr.operands[1],
1425
- o2_expr if o2_expr is not None else expr.operands[2],
1426
- ],
1427
- bits=expr.bits,
1428
- **expr.tags,
1429
- )
1430
-
1431
- return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, new_expr, self._codeloc())
1432
-
1433
- def _ail_handle_Concat(self, expr):
1434
- o0_value = self._expr(expr.operands[0])
1435
- o1_value = self._expr(expr.operands[1])
1436
-
1437
- value = self.state.top(expr.bits)
1438
- if o0_value is None or o1_value is None:
1439
- new_expr = expr
1440
- else:
1441
- o0_expr = o0_value.one_expr
1442
- o1_expr = o1_value.one_expr
1443
- new_expr = Expr.BinaryOp(
1444
- expr.idx,
1445
- "Concat",
1446
- [
1447
- o0_expr if o0_expr is not None else expr.operands[0],
1448
- o1_expr if o1_expr is not None else expr.operands[1],
1449
- ],
1450
- expr.signed,
1451
- **expr.tags,
1452
- )
1453
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1454
-
1455
- def _ail_handle_ExpCmpNE(self, expr):
1456
- o0_value = self._expr(expr.operands[0])
1457
- o1_value = self._expr(expr.operands[1])
1458
-
1459
- value = self.state.top(expr.bits)
1460
- if o0_value is None or o1_value is None:
1461
- new_expr = expr
1462
- else:
1463
- o0_expr = o0_value.one_expr
1464
- o1_expr = o1_value.one_expr
1465
- new_expr = Expr.BinaryOp(
1466
- expr.idx,
1467
- "ExpCmpNE",
1468
- [
1469
- o0_expr if o0_expr is not None else expr.operands[0],
1470
- o1_expr if o1_expr is not None else expr.operands[1],
1471
- ],
1472
- expr.signed,
1473
- **expr.tags,
1474
- )
1475
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1476
-
1477
- def _ail_handle_Clz(self, expr):
1478
- o0_value = self._expr(expr.operand)
1479
-
1480
- value = self.state.top(expr.bits)
1481
- if o0_value is None:
1482
- new_expr = expr
1483
- else:
1484
- o0_expr = o0_value.one_expr
1485
- new_expr = Expr.UnaryOp(
1486
- expr.idx,
1487
- "Clz",
1488
- o0_expr if o0_expr is not None else expr.operand,
1489
- **expr.tags,
1490
- )
1491
- return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
1492
-
1493
- #
1494
- # Util methods
1495
- #
1496
-
1497
- def is_using_outdated_def(
1498
- self,
1499
- expr: Expr.Expression,
1500
- expr_defat: CodeLocation | None,
1501
- current_loc: CodeLocation,
1502
- avoid: Expr.Expression | None = None,
1503
- ) -> tuple[bool, bool]:
1504
- if self._reaching_definitions is None:
1505
- l.warning(
1506
- "Reaching definition information is not provided to propagator. Assume the definition is out-dated."
1507
- )
1508
- return True, False
1509
-
1510
- if expr_defat is None:
1511
- # the definition originates outside the current node or function
1512
- l.warning("Unknown where the expression is defined. Assume the definition is out-dated.")
1513
- return True, False
1514
-
1515
- from .outdated_definition_walker import OutdatedDefinitionWalker # pylint:disable=import-outside-toplevel
1516
-
1517
- walker = OutdatedDefinitionWalker(
1518
- expr,
1519
- expr_defat,
1520
- current_loc,
1521
- self.state,
1522
- self.arch,
1523
- avoid=avoid,
1524
- extract_offset_to_sp=self.extract_offset_to_sp,
1525
- rda=self._reaching_definitions,
1526
- )
1527
- walker.walk_expression(expr)
1528
- return walker.out_dated, walker.has_avoid
1529
-
1530
- def should_force_replace(self, stmt: Stmt.Statement, new_expr: Expr.Expression) -> bool:
1531
- """
1532
- Determine if the expression should be replaced.
1533
-
1534
- We always replace the expression if:
1535
-
1536
- - the current statement is an indirect jump. this is to ensure the dynamically calculated jump targets are
1537
- always using the originally defined expressions, which usually leads to better decompilation output.
1538
- - the current statement is a return to make void functions (even when we incorrectly determine that they return
1539
- something) look better in general.
1540
- - the current statement has a shift-right operation and the source expression has a shift-right operation. this
1541
- is to support the peephole optimizations for division and modulo.
1542
-
1543
- :param stmt:
1544
- :param new_expr:
1545
- :return:
1546
- """
1547
- if isinstance(stmt, (Stmt.Jump, Stmt.Return)):
1548
- return True
1549
-
1550
- from angr.analyses.decompiler.counters.expression_counters import (
1551
- OperatorCounter,
1552
- ) # pylint:disable=wrong-import-position
1553
-
1554
- octr0 = OperatorCounter(["Shr", "Sar"], stmt)
1555
- octr1 = OperatorCounter(["Shr", "Sar"], new_expr)
1556
- return bool(octr0.count >= 1 and octr1.count >= 1 or octr0.count >= 2)
1557
-
1558
- @staticmethod
1559
- def has_tmpexpr(expr: Expr.Expression) -> bool:
1560
- from .tmpvar_finder import TmpvarFinder # pylint:disable=import-outside-toplevel
1561
-
1562
- return TmpvarFinder(expr).has_tmp