angr 9.2.131__py3-none-manylinux2014_aarch64.whl → 9.2.133__py3-none-manylinux2014_aarch64.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 (264) 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/misc/__init__.py +4 -4
  198. angr/misc/hookset.py +4 -5
  199. angr/misc/loggers.py +2 -2
  200. angr/misc/telemetry.py +1 -1
  201. angr/procedures/__init__.py +1 -1
  202. angr/procedures/cgc/fdwait.py +2 -2
  203. angr/procedures/definitions/__init__.py +2 -2
  204. angr/procedures/definitions/linux_kernel.py +0 -1
  205. angr/procedures/definitions/parse_syscalls_from_local_system.py +1 -1
  206. angr/procedures/definitions/parse_win32json.py +0 -1
  207. angr/procedures/ntdll/exceptions.py +1 -1
  208. angr/procedures/stubs/format_parser.py +3 -3
  209. angr/procedures/win32/dynamic_loading.py +1 -1
  210. angr/protos/__init__.py +3 -3
  211. angr/sim_manager.py +3 -5
  212. angr/sim_state.py +40 -42
  213. angr/sim_state_options.py +3 -3
  214. angr/sim_type.py +15 -14
  215. angr/sim_variable.py +42 -45
  216. angr/simos/__init__.py +4 -4
  217. angr/simos/cgc.py +1 -1
  218. angr/simos/simos.py +1 -1
  219. angr/simos/userland.py +1 -1
  220. angr/slicer.py +4 -7
  221. angr/state_plugins/__init__.py +34 -34
  222. angr/state_plugins/callstack.py +5 -12
  223. angr/state_plugins/heap/__init__.py +2 -2
  224. angr/state_plugins/heap/heap_brk.py +2 -4
  225. angr/state_plugins/heap/heap_ptmalloc.py +1 -1
  226. angr/state_plugins/jni_references.py +3 -2
  227. angr/state_plugins/scratch.py +1 -1
  228. angr/state_plugins/sim_action.py +1 -4
  229. angr/state_plugins/sim_event.py +1 -1
  230. angr/state_plugins/solver.py +7 -9
  231. angr/state_plugins/uc_manager.py +1 -1
  232. angr/state_plugins/view.py +2 -2
  233. angr/storage/__init__.py +1 -1
  234. angr/storage/file.py +10 -10
  235. angr/storage/memory_mixins/__init__.py +46 -46
  236. angr/storage/memory_mixins/default_filler_mixin.py +1 -3
  237. angr/storage/memory_mixins/javavm_memory_mixin.py +2 -2
  238. angr/storage/memory_mixins/name_resolution_mixin.py +2 -2
  239. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -3
  240. angr/storage/memory_mixins/paged_memory/pages/__init__.py +6 -6
  241. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  242. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +1 -1
  243. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  244. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  245. angr/storage/memory_mixins/regioned_memory/__init__.py +3 -3
  246. angr/storage/memory_mixins/regioned_memory/region_data.py +5 -5
  247. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +7 -9
  248. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +4 -4
  249. angr/storage/memory_object.py +4 -4
  250. angr/utils/__init__.py +3 -3
  251. angr/utils/bits.py +12 -0
  252. angr/utils/dynamic_dictlist.py +1 -1
  253. angr/utils/graph.py +1 -1
  254. angr/utils/orderedset.py +4 -1
  255. angr/utils/segment_list.py +2 -2
  256. angr/utils/ssa/__init__.py +33 -8
  257. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/METADATA +6 -6
  258. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/RECORD +262 -263
  259. angr/analyses/propagator/engine_ail.py +0 -1562
  260. angr/storage/memory_mixins/__init__.pyi +0 -48
  261. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/LICENSE +0 -0
  262. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/WHEEL +0 -0
  263. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/entry_points.txt +0 -0
  264. {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/top_level.txt +0 -0
@@ -1,54 +1,100 @@
1
- # pylint:disable=no-self-use,isinstance-second-argument-not-valid-type,unused-argument
1
+ # pylint:disable=no-self-use,unused-argument
2
2
  from __future__ import annotations
3
- from typing import Any
4
- import struct
3
+ from typing import Any, Protocol, cast, TypeVar, Generic
4
+ from collections.abc import Callable
5
+ from abc import abstractmethod
5
6
  import re
6
7
  import logging
7
8
 
8
9
  import ailment
9
10
  import pyvex
10
11
  import claripy
11
- import archinfo
12
+ from pyvex.expr import IRExpr
12
13
 
13
14
  from angr.misc.ux import once
14
- from angr.engines.vex.claripy.datalayer import value as claripy_value
15
15
  from angr.engines.vex.claripy.irop import UnsupportedIROpError, SimOperationError, vexop_to_simop
16
16
  from angr.code_location import CodeLocation
17
- from angr.utils.constants import DEFAULT_STATEMENT
18
- from angr.engines.engine import SimEngine
19
- import contextlib
17
+ from angr.project import Project
18
+ from angr.engines.engine import DataType_co, SimEngine, StateType
19
+ from angr.block import Block
20
20
 
21
21
 
22
- class SimEngineLightMixin:
22
+ class BlockProtocol(Protocol):
23
23
  """
24
- A mixin base class for engines meant to perform static analysis
24
+ The minimum protocol that a block an engine can process should adhere to.
25
+ Requires just an addr attribute.
25
26
  """
26
27
 
27
- def __init__(self, *args, logger=None, **kwargs):
28
- self.arch: archinfo.Arch | None = None
29
- self.l = logger
30
- super().__init__(*args, **kwargs)
28
+ addr: int
31
29
 
32
- def _is_top(self, expr) -> bool:
33
- """
34
- Check if a given expression is a TOP value.
35
30
 
36
- :param expr: The given expression.
37
- :return: True if the expression is TOP, False otherwise.
38
- """
39
- return False
31
+ BlockType = TypeVar("BlockType", bound=BlockProtocol)
32
+ ResultType = TypeVar("ResultType")
33
+ StmtDataType = TypeVar("StmtDataType")
40
34
 
41
- def _top(self, size: int):
42
- """
43
- Return a TOP value. It will only be called if _is_top() has been implemented.
44
35
 
45
- :param size: The size (in bits) of the TOP value.
46
- :return: A TOP value.
47
- """
48
- raise NotImplementedError
36
+ class IRTop(pyvex.expr.IRExpr):
37
+ """
38
+ A dummy IRExpr used for intra-engine communication and code-reuse.
39
+ """
40
+
41
+ def __init__(self, ty: str):
42
+ super().__init__()
43
+ self.ty = ty
44
+
45
+ def result_type(self, tyenv):
46
+ return self.ty
47
+
48
+
49
+ class SimEngineLight(Generic[StateType, DataType_co, BlockType, ResultType], SimEngine[StateType, ResultType]):
50
+ """
51
+ A full-featured engine base class, suitable for static analysis
52
+ """
53
+
54
+ # local variables
55
+ block: BlockType
56
+ _call_stack: list[Any]
57
+ state: StateType
58
+
59
+ stmt_idx: int
60
+ ins_addr: int
61
+ tmps: dict[int, DataType_co]
62
+
63
+ def __init__(self, project: Project, logger=None):
64
+ self.l = logger or logging.getLogger(self.__module__ + "." + self.__class__.__name__)
65
+ super().__init__(project)
66
+
67
+ # there's two of these to support the mixin pattern - mixins can override process while there must be some base
68
+ # class that provides _process
69
+ def process(self, state: StateType, *, block: BlockType | None = None, **kwargs) -> ResultType:
70
+ return self._process(state, block=block, **kwargs)
71
+
72
+ @abstractmethod
73
+ def _process(self, state: StateType, *, block: BlockType | None = None, **kwargs) -> ResultType: ...
74
+
75
+ def lift(self, state: StateType) -> BlockType:
76
+ raise TypeError(f"{type(self)} requires `block` to be passed to `process`")
77
+
78
+ #
79
+ # Helper methods
80
+ #
81
+
82
+ def _codeloc(self, block_only=False, context=None):
83
+ return CodeLocation(
84
+ self.block.addr,
85
+ None if block_only else self.stmt_idx,
86
+ ins_addr=None if block_only else self.ins_addr,
87
+ context=context,
88
+ )
89
+
90
+ @abstractmethod
91
+ def _top(self, bits: int) -> DataType_co: ...
92
+
93
+ @abstractmethod
94
+ def _is_top(self, expr: Any) -> bool: ...
49
95
 
50
96
  @staticmethod
51
- def sp_offset(bits: int, offset: int):
97
+ def sp_offset(bits: int, offset: int) -> claripy.ast.BV:
52
98
  base = claripy.BVS("SpOffset", bits, explicit_name=True)
53
99
  if offset:
54
100
  base += offset
@@ -73,92 +119,180 @@ class SimEngineLightMixin:
73
119
  # Unexpected but fine
74
120
  return 0
75
121
  if isinstance(spoffset_expr.args[1], claripy.ast.Base) and spoffset_expr.args[1].op == "BVV":
76
- return spoffset_expr.args[1].args[0]
122
+ return cast(int, spoffset_expr.args[1].args[0])
77
123
  elif spoffset_expr.op == "__sub__":
78
124
  if len(spoffset_expr.args) == 1:
79
125
  # Unexpected but fine
80
126
  return 0
81
127
  if isinstance(spoffset_expr.args[1], claripy.ast.Base) and spoffset_expr.args[1].op == "BVV":
82
- return -spoffset_expr.args[1].args[0] & ((1 << spoffset_expr.size()) - 1)
128
+ return -cast(int, spoffset_expr.args[1].args[0]) & (
129
+ (1 << cast(claripy.ast.BV, spoffset_expr).size()) - 1
130
+ )
83
131
  return None
84
132
 
85
133
 
86
- class SimEngineLight(
87
- SimEngineLightMixin,
88
- SimEngine,
134
+ T = TypeVar("T")
135
+
136
+
137
+ def longest_prefix_lookup(haystack: str, mapping: dict[str, T]) -> T | None:
138
+ for l in reversed(range(len(haystack))):
139
+ handler = mapping.get(haystack[:l], None)
140
+ if handler is not None:
141
+ return handler
142
+ return None
143
+
144
+
145
+ # noinspection PyPep8Naming
146
+ class SimEngineLightVEX(
147
+ Generic[StateType, DataType_co, ResultType, StmtDataType], SimEngineLight[StateType, DataType_co, Block, ResultType]
89
148
  ):
90
149
  """
91
- A full-featured engine base class, suitable for static analysis
150
+ A mixin for doing static analysis on VEX
92
151
  """
93
152
 
94
- def __init__(self):
95
- logger = logging.getLogger(self.__module__ + "." + self.__class__.__name__)
96
- super().__init__(logger=logger)
153
+ tyenv: pyvex.IRTypeEnv
97
154
 
98
- # local variables
99
- self.state = None
100
- self.arch: archinfo.Arch = None
101
- self.block = None
102
- self._call_stack = None
103
-
104
- self.stmt_idx = None
105
- self.ins_addr = None
106
- self.tmps = None
155
+ @staticmethod
156
+ def unop_handler(f: Callable[[T, pyvex.expr.Unop], DataType_co]) -> Callable[[T, pyvex.expr.Unop], DataType_co]:
157
+ f.unop_handler = True
158
+ return f
107
159
 
108
- # for VEX blocks only
109
- self.tyenv = None
160
+ @staticmethod
161
+ def binop_handler(f: Callable[[T, pyvex.expr.Binop], DataType_co]) -> Callable[[T, pyvex.expr.Binop], DataType_co]:
162
+ f.binop_handler = True
163
+ return f
110
164
 
111
- def process(self, state, *args, **kwargs):
112
- # we are using a completely different state. Therefore, we directly call our _process() method before
113
- # SimEngine becomes flexible enough.
114
- self._process(state, None, block=kwargs.pop("block", None), whitelist=kwargs.pop("whitelist", None))
165
+ @staticmethod
166
+ def binopv_handler(
167
+ f: Callable[[T, int, int, pyvex.expr.Binop], DataType_co]
168
+ ) -> Callable[[T, int, int, pyvex.expr.Binop], DataType_co]:
169
+ f.binopv_handler = True
170
+ return f
115
171
 
116
- def _process(self, new_state, successors, *args, **kwargs):
117
- raise NotImplementedError
172
+ @staticmethod
173
+ def triop_handler(f: Callable[[T, pyvex.expr.Triop], DataType_co]) -> Callable[[T, pyvex.expr.Triop], DataType_co]:
174
+ f.triop_handler = True
175
+ return f
118
176
 
119
- def _check(self, state, *args, **kwargs):
120
- return True
177
+ @staticmethod
178
+ def qop_handler(f: Callable[[T, pyvex.expr.Qop], DataType_co]) -> Callable[[T, pyvex.expr.Qop], DataType_co]:
179
+ f.qop_handler = True
180
+ return f
121
181
 
122
- #
123
- # Helper methods
124
- #
182
+ @staticmethod
183
+ def ccall_handler(f: Callable[[T, pyvex.expr.CCall], DataType_co]) -> Callable[[T, pyvex.expr.CCall], DataType_co]:
184
+ f.ccall_handler = True
185
+ return f
125
186
 
126
- def _codeloc(self, block_only=False, context=None):
127
- return CodeLocation(
128
- self.block.addr,
129
- None if block_only else self.stmt_idx,
130
- ins_addr=None if block_only else self.ins_addr,
131
- context=context,
132
- )
187
+ @staticmethod
188
+ def dirty_handler(
189
+ f: Callable[[T, pyvex.stmt.Dirty], StmtDataType]
190
+ ) -> Callable[[T, pyvex.stmt.Dirty], StmtDataType]:
191
+ f.dirty_handler = True
192
+ return f
133
193
 
194
+ def __init__(self, *args, **kwargs):
195
+ super().__init__(*args, **kwargs)
134
196
 
135
- # noinspection PyPep8Naming
136
- class SimEngineLightVEXMixin(SimEngineLightMixin):
137
- """
138
- A mixin for doing static analysis on VEX
139
- """
197
+ def checked(h: T, attr: str) -> T:
198
+ if not getattr(h, attr, False):
199
+ raise TypeError(f"Handle {h} is not validated for {attr}")
200
+ return h
201
+
202
+ self._stmt_handlers: dict[str, Callable[[Any], StmtDataType]] = {
203
+ "Ist_WrTmp": self._handle_stmt_WrTmp,
204
+ "Ist_Put": self._handle_stmt_Put,
205
+ "Ist_PutI": self._handle_stmt_PutI,
206
+ "Ist_Store": self._handle_stmt_Store,
207
+ "Ist_StoreG": self._handle_stmt_StoreG,
208
+ "Ist_LoadG": self._handle_stmt_LoadG,
209
+ "Ist_CAS": self._handle_stmt_CAS,
210
+ "Ist_LLSC": self._handle_stmt_LLSC,
211
+ "Ist_MBE": self._handle_stmt_MBE,
212
+ "Ist_Exit": self._handle_stmt_Exit,
213
+ "Ist_NoOp": self._handle_stmt_NoOp,
214
+ "Ist_IMark": self._handle_stmt_IMark,
215
+ "Ist_AbiHint": self._handle_stmt_AbiHint,
216
+ "Ist_Dirty": self._handle_stmt_Dirty,
217
+ }
218
+ self._expr_handlers: dict[str, Callable[[Any], DataType_co]] = {
219
+ "IRTop": self._handle_expr_IRTop,
220
+ "VECRET": self._handle_expr_VECRET,
221
+ "GSPTR": self._handle_expr_GSPTR,
222
+ "RdTmp": self._handle_expr_RdTmp,
223
+ "Get": self._handle_expr_Get,
224
+ "GetI": self._handle_expr_GetI,
225
+ "Load": self._handle_expr_Load,
226
+ "ITE": self._handle_expr_ITE,
227
+ "Unop": self._handle_expr_Unop,
228
+ "Binop": self._handle_expr_Binop,
229
+ "Triop": self._handle_expr_Triop,
230
+ "Qop": self._handle_expr_Qop,
231
+ "CCall": self._handle_expr_CCall,
232
+ "Const": self._handle_expr_Const,
233
+ }
234
+ self._unop_handlers: dict[str, Callable[[pyvex.expr.Unop], DataType_co]] = {
235
+ name.split("_", 3)[-1]: checked(getattr(self, name), "unop_handler")
236
+ for name in dir(self)
237
+ if name.startswith("_handle_unop_")
238
+ }
239
+ self._binop_handlers: dict[str, Callable[[pyvex.expr.Binop], DataType_co]] = {
240
+ name.split("_", 3)[-1]: checked(getattr(self, name), "binop_handler")
241
+ for name in dir(self)
242
+ if name.startswith("_handle_binop_")
243
+ }
244
+ self._binopv_handlers: dict[str, Callable[[int, int, pyvex.expr.Binop], DataType_co]] = {
245
+ name.split("_", 3)[-1]: checked(getattr(self, name), "binopv_handler")
246
+ for name in dir(self)
247
+ if name.startswith("_handle_binopv_")
248
+ }
249
+ self._triop_handlers: dict[str, Callable[[pyvex.expr.Triop], DataType_co]] = {
250
+ name.split("_", 3)[-1]: checked(getattr(self, name), "triop_handler")
251
+ for name in dir(self)
252
+ if name.startswith("_handle_triop_")
253
+ }
254
+ self._qop_handlers: dict[str, Callable[[pyvex.expr.Qop], DataType_co]] = {
255
+ name.split("_", 3)[-1]: checked(getattr(self, name), "qop_handler")
256
+ for name in dir(self)
257
+ if name.startswith("_handle_qop_")
258
+ }
259
+ self._ccall_handlers: dict[str, Callable[[pyvex.expr.CCall], DataType_co]] = {
260
+ name.split("_", 3)[-1]: checked(getattr(self, name), "ccall_handler")
261
+ for name in dir(self)
262
+ if name.startswith("_handle_ccall_")
263
+ }
264
+ self._dirty_handlers: dict[str, Callable[[pyvex.stmt.Dirty], StmtDataType]] = {
265
+ name.split("_", 3)[-1]: checked(getattr(self, name), "dirty_handler")
266
+ for name in dir(self)
267
+ if name.startswith("_handle_dirty_")
268
+ }
140
269
 
141
- def _process(self, state, successors, *args, block, whitelist=None, **kwargs): # pylint:disable=arguments-differ
270
+ def _process(
271
+ self, state: StateType, *, block: Block | None = None, whitelist: set[int] | None = None, **kwargs
272
+ ) -> ResultType:
142
273
  # initialize local variables
143
274
  self.tmps = {}
275
+
276
+ if block is None:
277
+ block = self.lift(state)
144
278
  self.block = block
145
279
  self.state = state
146
-
147
- if state is not None:
148
- self.arch: archinfo.Arch = state.arch
149
-
280
+ self.arch = self.project.arch
150
281
  self.tyenv = block.vex.tyenv
151
-
152
- self._process_Stmt(whitelist=whitelist)
153
-
154
- self.stmt_idx = None
155
- self.ins_addr = None
156
-
157
- def _process_Stmt(self, whitelist=None):
158
- if whitelist is not None:
159
- # optimize whitelist lookups
160
- whitelist = set(whitelist)
161
-
282
+ self.stmt_idx = -1
283
+ self.ins_addr = -1
284
+
285
+ result = self._process_block(whitelist=whitelist)
286
+ del self.stmt_idx
287
+ del self.ins_addr
288
+ del self.tmps
289
+ del self.block
290
+ del self.state
291
+ del self.tyenv
292
+ return result
293
+
294
+ def _process_block(self, whitelist: set[int] | None = None) -> ResultType:
295
+ result = []
162
296
  for stmt_idx, stmt in enumerate(self.block.vex.statements):
163
297
  if whitelist is not None and stmt_idx not in whitelist:
164
298
  continue
@@ -169,1290 +303,974 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
169
303
  # The bug caused by skipping IMarks is reported at https://github.com/angr/angr/pull/1150
170
304
  self.ins_addr = stmt.addr + stmt.delta
171
305
 
172
- self._handle_Stmt(stmt)
173
-
174
- self._process_block_end()
175
-
176
- def _process_block_end(self):
177
- # handle calls to another function
178
- # Note that without global information, we cannot handle cases where we *jump* to another function (jumpkind ==
179
- # "Ijk_Boring"). Users are supposed to overwrite this method, detect these cases with the help of global
180
- # information (such as CFG or symbol addresses), and handle them accordingly.
181
- if self.block.vex.jumpkind == "Ijk_Call":
182
- self.stmt_idx = DEFAULT_STATEMENT
183
- handler = "_handle_function"
184
- if hasattr(self, handler):
185
- func_addr = (
186
- self.block.vex.next if isinstance(self.block.vex.next, int) else self._expr(self.block.vex.next)
187
- )
188
- if func_addr is None and self.l is not None:
189
- self.l.debug("Cannot determine the callee address at %#x.", self.block.addr)
190
- getattr(self, handler)(func_addr)
191
- else:
192
- if self.l is not None:
193
- self.l.warning("Function handler not implemented.")
306
+ result.append(self._stmt(stmt))
307
+
308
+ return self._process_block_end(result, whitelist)
309
+
310
+ def _stmt(self, stmt: pyvex.stmt.IRStmt) -> StmtDataType:
311
+ return self._stmt_handlers[stmt.tag](stmt)
312
+
313
+ @abstractmethod
314
+ def _process_block_end(self, stmt_result: list[StmtDataType], whitelist: set[int] | None) -> ResultType: ...
194
315
 
195
316
  #
196
317
  # Statement handlers
197
318
  #
198
319
 
199
- def _handle_Stmt(self, stmt):
200
- handler = f"_handle_{type(stmt).__name__}"
201
- if hasattr(self, handler):
202
- getattr(self, handler)(stmt)
203
- elif type(stmt).__name__ not in ("IMark", "AbiHint") and self.l is not None:
204
- self.l.error("Unsupported statement type %s.", type(stmt).__name__)
320
+ @abstractmethod
321
+ def _handle_stmt_WrTmp(self, stmt: pyvex.stmt.WrTmp) -> StmtDataType: ...
322
+
323
+ @abstractmethod
324
+ def _handle_stmt_Put(self, stmt: pyvex.stmt.Put) -> StmtDataType: ...
325
+
326
+ @abstractmethod
327
+ def _handle_stmt_PutI(self, stmt: pyvex.stmt.PutI) -> StmtDataType: ...
205
328
 
206
- # synchronize with function _handle_WrTmpData()
207
- def _handle_WrTmp(self, stmt):
208
- data = self._expr(stmt.data)
209
- if data is None:
210
- return
329
+ @abstractmethod
330
+ def _handle_stmt_Store(self, stmt: pyvex.stmt.Store) -> StmtDataType: ...
211
331
 
212
- self.tmps[stmt.tmp] = data
332
+ @abstractmethod
333
+ def _handle_stmt_StoreG(self, stmt: pyvex.stmt.StoreG) -> StmtDataType: ...
213
334
 
214
- # invoked by LoadG
215
- def _handle_WrTmpData(self, tmp, data):
216
- if data is None:
217
- return
218
- self.tmps[tmp] = data
335
+ @abstractmethod
336
+ def _handle_stmt_LoadG(self, stmt: pyvex.stmt.LoadG) -> StmtDataType: ...
219
337
 
220
- def _handle_Dirty(self, stmt):
221
- if self.l is not None:
222
- self.l.error("Unimplemented Dirty node for current architecture.")
338
+ @abstractmethod
339
+ def _handle_stmt_CAS(self, stmt: pyvex.stmt.CAS) -> StmtDataType: ...
223
340
 
224
- def _handle_Put(self, stmt):
225
- raise NotImplementedError("Please implement the Put handler with your own logic.")
341
+ @abstractmethod
342
+ def _handle_stmt_LLSC(self, stmt: pyvex.stmt.LLSC) -> StmtDataType: ...
226
343
 
227
- def _handle_Store(self, stmt):
228
- raise NotImplementedError("Please implement the Store handler with your own logic.")
344
+ @abstractmethod
345
+ def _handle_stmt_MBE(self, stmt: pyvex.stmt.MBE) -> StmtDataType: ...
229
346
 
230
- def _handle_StoreG(self, stmt):
231
- raise NotImplementedError("Please implement the StoreG handler with your own logic.")
347
+ @abstractmethod
348
+ def _handle_stmt_Exit(self, stmt: pyvex.stmt.Exit) -> StmtDataType: ...
232
349
 
233
- def _handle_LLSC(self, stmt: pyvex.IRStmt.LLSC):
234
- raise NotImplementedError("Please implement the LLSC handler with your own logic.")
350
+ @abstractmethod
351
+ def _handle_stmt_NoOp(self, stmt: pyvex.stmt.NoOp) -> StmtDataType: ...
352
+
353
+ @abstractmethod
354
+ def _handle_stmt_IMark(self, stmt: pyvex.stmt.IMark) -> StmtDataType: ...
355
+
356
+ @abstractmethod
357
+ def _handle_stmt_AbiHint(self, stmt: pyvex.stmt.AbiHint) -> StmtDataType: ...
358
+
359
+ def _handle_stmt_Dirty(self, stmt: pyvex.stmt.Dirty) -> StmtDataType:
360
+ handler = longest_prefix_lookup(stmt.cee.name, self._dirty_handlers)
361
+ if handler is not None:
362
+ return handler(stmt)
363
+
364
+ if once(stmt.cee.name) and self.l is not None:
365
+ self.l.error("Unsupported Dirty %s.", stmt.cee.name)
366
+ if stmt.tmp in (-1, 0xFFFFFFFF):
367
+ return self._handle_stmt_NoOp(pyvex.stmt.NoOp())
368
+ return self._handle_stmt_WrTmp(pyvex.stmt.WrTmp(stmt.tmp, IRTop(self.tyenv.lookup(stmt.tmp))))
235
369
 
236
370
  #
237
371
  # Expression handlers
238
372
  #
239
373
 
240
- def _expr(self, expr):
241
- handler = f"_handle_{type(expr).__name__}"
242
- if hasattr(self, handler):
243
- return getattr(self, handler)(expr)
244
- if self.l is not None:
245
- self.l.error("Unsupported expression type %s.", type(expr).__name__)
246
- return None
374
+ def _expr(self, expr: IRExpr) -> DataType_co:
375
+ handler = type(expr).__name__
376
+ return self._expr_handlers[handler](expr)
247
377
 
248
- def _handle_Triop(self, expr: pyvex.IRExpr.Triop): # pylint: disable=useless-return
378
+ # not generated by vex
379
+ def _handle_expr_IRTop(self, expr: IRTop) -> DataType_co:
380
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
381
+
382
+ @abstractmethod
383
+ def _handle_expr_VECRET(self, expr: pyvex.expr.VECRET) -> DataType_co: ...
384
+
385
+ @abstractmethod
386
+ def _handle_expr_GSPTR(self, expr: pyvex.expr.GSPTR) -> DataType_co: ...
387
+
388
+ @abstractmethod
389
+ def _handle_expr_RdTmp(self, expr: pyvex.expr.RdTmp) -> DataType_co: ...
390
+
391
+ @abstractmethod
392
+ def _handle_expr_Get(self, expr: pyvex.expr.Get) -> DataType_co: ...
393
+
394
+ @abstractmethod
395
+ def _handle_expr_GetI(self, expr: pyvex.expr.GetI) -> DataType_co: ...
396
+
397
+ @abstractmethod
398
+ def _handle_expr_Load(self, expr: pyvex.expr.Load) -> DataType_co: ...
399
+
400
+ @abstractmethod
401
+ def _handle_expr_ITE(self, expr: pyvex.expr.ITE) -> DataType_co: ...
402
+
403
+ def _handle_expr_Unop(self, expr: pyvex.expr.Unop) -> DataType_co:
249
404
  handler = None
250
- if expr.op.startswith("Iop_AddF") or expr.op.startswith("Iop_SubF"):
251
- handler = "_handle_AddF"
252
- elif expr.op.startswith("Iop_MulF"):
253
- handler = "_handle_MulF"
254
- elif expr.op.startswith("Iop_DivF"):
255
- handler = "_handle_DivF"
256
- elif expr.op.startswith("Iop_SinF"):
257
- handler = "_handle_SinF"
258
- elif expr.op.startswith("Iop_ScaleF"):
259
- handler = "_handle_ScaleF"
260
-
261
- if handler is not None and hasattr(self, handler):
262
- return getattr(self, handler)(expr)
405
+ assert expr.op.startswith("Iop_")
406
+ handler = longest_prefix_lookup(expr.op[4:], self._unop_handlers)
407
+ if handler is not None:
408
+ return handler(expr)
409
+
410
+ # All conversions are handled by the Conversion handler
411
+ try:
412
+ simop = vexop_to_simop(expr.op)
413
+ except (UnsupportedIROpError, SimOperationError):
414
+ simop = None
415
+
416
+ if simop is not None and "Reinterp" not in expr.op and simop.op_attrs.get("conversion", None):
417
+ return self._handle_conversion(simop._from_size, simop._to_size, simop.is_signed, expr.args[0])
418
+
419
+ if once(expr.op) and self.l is not None:
420
+ self.l.error("Unsupported Unop %s.", expr.op)
421
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
422
+
423
+ @abstractmethod
424
+ def _handle_conversion(self, from_size: int, to_size: int, signed: bool, operand: IRExpr) -> DataType_co: ...
425
+
426
+ def _handle_expr_Binop(self, expr: pyvex.expr.Binop) -> DataType_co:
427
+ assert expr.op.startswith("Iop_")
428
+
429
+ # vector information
430
+ m = re.match(r"Iop_[^\d]+(\d+)[SU]{0,1}x(\d+)", expr.op)
431
+ if m is not None:
432
+ vector_size = int(m.group(1))
433
+ vector_count = int(m.group(2))
434
+ handler_v = longest_prefix_lookup(expr.op[4:], self._binopv_handlers)
435
+ if handler_v is not None:
436
+ return handler_v(vector_size, vector_count, expr)
437
+
438
+ handler = longest_prefix_lookup(expr.op[4:], self._binop_handlers)
439
+ if handler is not None:
440
+ return handler(expr)
441
+
442
+ if once(expr.op) and self.l is not None:
443
+ self.l.warning("Unsupported Binop %s.", expr.op)
444
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
445
+
446
+ def _handle_expr_Triop(self, expr: pyvex.expr.Triop) -> DataType_co:
447
+ assert expr.op.startswith("Iop_")
448
+ handler = longest_prefix_lookup(expr.op[4:], self._triop_handlers)
449
+ if handler is not None:
450
+ return handler(expr)
451
+
452
+ # should we try dispatching some triops with roundingmode as binops?
263
453
 
264
454
  if once(expr.op) and self.l is not None:
265
455
  self.l.error("Unsupported Triop %s.", expr.op)
456
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
266
457
 
267
- return None
458
+ def _handle_expr_Qop(self, expr: pyvex.expr.Qop) -> DataType_co:
459
+ assert expr.op.startswith("Iop_")
460
+ handler = longest_prefix_lookup(expr.op[4:], self._qop_handlers)
461
+ if handler is not None:
462
+ return handler(expr)
268
463
 
269
- def _handle_AddF(self, expr):
270
- return self._top(expr.result_size(self.tyenv))
464
+ if once(expr.op) and self.l is not None:
465
+ self.l.error("Unsupported Qop %s.", expr.op)
466
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
271
467
 
272
- def _handle_SubF(self, expr):
273
- return self._top(expr.result_size(self.tyenv))
468
+ def _handle_expr_CCall(self, expr: pyvex.expr.CCall) -> DataType_co: # pylint:disable=useless-return
469
+ handler = longest_prefix_lookup(expr.cee.name, self._ccall_handlers)
470
+ if handler is not None:
471
+ return handler(expr)
274
472
 
275
- def _handle_MulF(self, expr):
276
- return self._top(expr.result_size(self.tyenv))
473
+ if once(expr.cee.name) and self.l is not None:
474
+ self.l.error("Unsupported CCall %s.", expr.cee.name)
475
+ return self._top(pyvex.get_type_size(expr.result_type(self.tyenv)))
277
476
 
278
- def _handle_DivF(self, expr):
279
- return self._top(expr.result_size(self.tyenv))
477
+ @abstractmethod
478
+ def _handle_expr_Const(self, expr: pyvex.expr.Const) -> DataType_co: ...
280
479
 
281
- def _handle_NegF(self, expr):
282
- return self._top(expr.result_size(self.tyenv))
283
480
 
284
- def _handle_AbsF(self, expr):
285
- return self._top(expr.result_size(self.tyenv))
481
+ class SimEngineNostmtVEX(
482
+ Generic[StateType, DataType_co, ResultType], SimEngineLightVEX[StateType, DataType_co, ResultType, None]
483
+ ):
484
+ """
485
+ A base class of SimEngineLightVEX that has default handlers for statements if they just need to return None, so you
486
+ don't have to implement every single statement handler as ``return None``.
487
+ """
286
488
 
287
- def _handle_SinF(self, expr):
288
- return self._top(expr.result_size(self.tyenv))
489
+ def _handle_stmt_WrTmp(self, stmt):
490
+ pass
289
491
 
290
- def _handle_CosF(self, expr):
291
- return self._top(expr.result_size(self.tyenv))
492
+ def _handle_stmt_Put(self, stmt):
493
+ pass
292
494
 
293
- def _handle_ScaleF(self, expr):
294
- return self._top(expr.result_size(self.tyenv))
495
+ def _handle_stmt_PutI(self, stmt):
496
+ pass
295
497
 
296
- def _handle_RdTmp(self, expr):
297
- tmp = expr.tmp
498
+ def _handle_stmt_Store(self, stmt):
499
+ pass
298
500
 
299
- if tmp in self.tmps:
300
- return self.tmps[tmp]
301
- return None
501
+ def _handle_stmt_StoreG(self, stmt):
502
+ pass
302
503
 
303
- def _handle_Get(self, expr):
304
- raise NotImplementedError("Please implement the Get handler with your own logic.")
504
+ def _handle_stmt_LoadG(self, stmt):
505
+ pass
305
506
 
306
- def _handle_Load(self, expr):
307
- raise NotImplementedError("Please implement the Load handler with your own logic.")
507
+ def _handle_stmt_CAS(self, stmt):
508
+ pass
308
509
 
309
- def _handle_LoadG(self, stmt):
310
- raise NotImplementedError("Please implement the LoadG handler with your own logic.")
510
+ def _handle_stmt_LLSC(self, stmt):
511
+ pass
311
512
 
312
- def _handle_Exit(self, stmt):
313
- self._expr(stmt.guard)
314
- self._expr(stmt.dst)
513
+ def _handle_stmt_MBE(self, stmt):
514
+ pass
315
515
 
316
- def _handle_ITE(self, expr):
317
- # EDG says: Not sure how generic this is.
318
- cond = self._expr(expr.cond)
319
- if cond is True:
320
- return self._expr(expr.iftrue)
321
- if cond is False:
322
- return self._expr(expr.iffalse)
323
- return None
516
+ def _handle_stmt_Exit(self, stmt):
517
+ pass
324
518
 
325
- def _handle_Unop(self, expr):
326
- handler = None
519
+ def _handle_stmt_NoOp(self, stmt):
520
+ pass
327
521
 
328
- # All conversions are handled by the Conversion handler
329
- simop = None
330
- with contextlib.suppress(UnsupportedIROpError, SimOperationError):
331
- simop = vexop_to_simop(expr.op)
522
+ def _handle_stmt_IMark(self, stmt):
523
+ pass
332
524
 
333
- if simop is not None and simop.op_attrs.get("conversion", None):
334
- handler = "_handle_Conversion"
335
- # Notice order of "Not" comparisons
336
- elif expr.op == "Iop_Not1":
337
- handler = "_handle_Not1"
338
- elif expr.op.startswith("Iop_Not"):
339
- handler = "_handle_Not"
340
- elif expr.op.startswith("Iop_Clz"):
341
- handler = "_handle_Clz"
342
- elif expr.op.startswith("Iop_Ctz"):
343
- handler = "_handle_Ctz"
344
- elif expr.op.startswith("Iop_NegF"):
345
- handler = "_handle_NegF"
346
- elif expr.op.startswith("Iop_AbsF"):
347
- handler = "_handle_AbsF"
348
-
349
- if handler is not None and hasattr(self, handler):
350
- return getattr(self, handler)(expr)
351
- if self.l is not None:
352
- self.l.error("Unsupported Unop %s.", expr.op)
353
- return None
525
+ def _handle_stmt_AbiHint(self, stmt):
526
+ pass
354
527
 
355
- def _handle_Binop(self, expr: pyvex.IRExpr.Binop):
356
- handler = None
357
- if expr.op.startswith("Iop_And"):
358
- handler = "_handle_And"
359
- elif expr.op.startswith("Iop_Mod"):
360
- handler = "_handle_Mod"
361
- elif expr.op.startswith("Iop_Or"):
362
- handler = "_handle_Or"
363
- elif expr.op.startswith("Iop_Add"):
364
- handler = "_handle_Add"
365
- elif expr.op.startswith("Iop_HAdd"):
366
- handler = "_handle_HAdd"
367
- elif expr.op.startswith("Iop_Sub"):
368
- handler = "_handle_Sub"
369
- elif expr.op.startswith("Iop_QSub"):
370
- handler = "_handle_QSub"
371
- elif expr.op.startswith("Iop_Mull"):
372
- handler = "_handle_Mull"
373
- elif expr.op.startswith("Iop_Mul"):
374
- handler = "_handle_Mul"
375
- elif expr.op.startswith("Iop_DivMod"):
376
- handler = "_handle_DivMod"
377
- elif expr.op.startswith("Iop_Div"):
378
- handler = "_handle_Div"
379
- elif expr.op.startswith("Iop_Xor"):
380
- handler = "_handle_Xor"
381
- elif expr.op.startswith("Iop_Shl"):
382
- handler = "_handle_Shl"
383
- elif expr.op.startswith("Iop_Shr"):
384
- handler = "_handle_Shr"
385
- elif expr.op.startswith("Iop_Sal"):
386
- # intended use of SHL
387
- handler = "_handle_Shl"
388
- elif expr.op.startswith("Iop_Sar"):
389
- handler = "_handle_Sar"
390
- elif expr.op.startswith("Iop_CmpEQ"):
391
- handler = "_handle_CmpEQ"
392
- elif expr.op.startswith("Iop_CmpNE"):
393
- handler = "_handle_CmpNE"
394
- elif expr.op.startswith("Iop_CmpLT"):
395
- handler = "_handle_CmpLT"
396
- elif expr.op.startswith("Iop_CmpLE"):
397
- handler = "_handle_CmpLE"
398
- elif expr.op.startswith("Iop_CmpGE"):
399
- handler = "_handle_CmpGE"
400
- elif expr.op.startswith("Iop_CmpGT"):
401
- handler = "_handle_CmpGT"
402
- elif expr.op.startswith("Iop_CmpORD"):
403
- handler = "_handle_CmpORD"
404
- elif expr.op.startswith("Iop_CmpF"):
405
- handler = "_handle_CmpF"
406
- elif expr.op == "Iop_32HLto64":
407
- handler = "_handle_32HLto64"
408
- elif expr.op.startswith("Const"):
409
- handler = "_handle_Const"
410
- elif expr.op.startswith("Iop_16HLto32"):
411
- handler = "_handle_16HLto32"
412
- elif expr.op.startswith("Iop_ExpCmpNE64"):
413
- handler = "_handle_ExpCmpNE64"
414
- elif expr.op.startswith("Iop_SinF"):
415
- handler = "_handle_SinF"
416
- elif expr.op.startswith("Iop_CosF"):
417
- handler = "_handle_CosF"
418
-
419
- vector_size, vector_count = None, None
420
- if handler is not None:
421
- # vector information
422
- m = re.match(r"Iop_[^\d]+(\d+)[SU]{0,1}x(\d+)", expr.op)
423
- if m is not None:
424
- vector_size = int(m.group(1))
425
- vector_count = int(m.group(2))
426
- handler += "_v"
427
-
428
- if handler is not None and hasattr(self, handler):
429
- if vector_size is not None and vector_count is not None:
430
- return getattr(self, handler)(expr, vector_size, vector_count)
431
- return getattr(self, handler)(expr)
432
- if once(expr.op) and self.l is not None:
433
- self.l.warning("Unsupported Binop %s.", expr.op)
434
528
 
435
- return None
529
+ # noinspection PyPep8Naming
530
+ class SimEngineLightAIL(
531
+ Generic[StateType, DataType_co, StmtDataType, ResultType],
532
+ SimEngineLight[StateType, DataType_co, ailment.Block, ResultType],
533
+ ):
534
+ """
535
+ A mixin for doing static analysis on AIL
536
+ """
537
+
538
+ def __init__(self, *args, **kwargs):
539
+ self._stmt_handlers: dict[str, Callable[[Any], StmtDataType]] = {
540
+ "Assignment": self._handle_stmt_Assignment,
541
+ "Store": self._handle_stmt_Store,
542
+ "Jump": self._handle_stmt_Jump,
543
+ "ConditionalJump": self._handle_stmt_ConditionalJump,
544
+ "Call": self._handle_stmt_Call,
545
+ "Return": self._handle_stmt_Return,
546
+ "DirtyStatement": self._handle_stmt_DirtyStatement,
547
+ "Label": self._handle_stmt_Label,
548
+ }
549
+ self._expr_handlers: dict[str, Callable[[Any], DataType_co]] = {
550
+ "Atom": self._handle_expr_Atom,
551
+ "Const": self._handle_expr_Const,
552
+ "Tmp": self._handle_expr_Tmp,
553
+ "VirtualVariable": self._handle_expr_VirtualVariable,
554
+ "Phi": self._handle_expr_Phi,
555
+ "Op": self._handle_expr_Op,
556
+ "UnaryOp": self._handle_expr_UnaryOp,
557
+ "BinaryOp": self._handle_expr_BinaryOp,
558
+ "Convert": self._handle_expr_Convert,
559
+ "Reinterpret": self._handle_expr_Reinterpret,
560
+ "Load": self._handle_expr_Load,
561
+ "Register": self._handle_expr_Register,
562
+ "ITE": self._handle_expr_ITE,
563
+ "Call": self._handle_expr_Call,
564
+ "DirtyExpression": self._handle_expr_DirtyExpression,
565
+ "VEXCCallExpression": self._handle_expr_VEXCCallExpression,
566
+ "MultiStatementExpression": self._handle_expr_MultiStatementExpression,
567
+ "BasePointerOffset": self._handle_expr_BasePointerOffset,
568
+ "StackBaseOffset": self._handle_expr_StackBaseOffset,
569
+ }
570
+ self._unop_handlers: dict[str, Callable[[ailment.UnaryOp], DataType_co]] = {
571
+ "Not": self._handle_unop_Not,
572
+ "Neg": self._handle_unop_Neg,
573
+ "BitwiseNeg": self._handle_unop_BitwiseNeg,
574
+ "Reference": self._handle_unop_Reference,
575
+ "Dereference": self._handle_unop_Dereference,
576
+ "Clz": self._handle_unop_Clz,
577
+ "Ctz": self._handle_unop_Ctz,
578
+ "GetMSBs": self._handle_unop_GetMSBs,
579
+ "unpack": self._handle_unop_unpack,
580
+ "Sqrt": self._handle_unop_Sqrt,
581
+ "RSqrtEst": self._handle_unop_RSqrtEst,
582
+ }
583
+ self._binop_handlers: dict[str, Callable[[ailment.BinaryOp], DataType_co]] = {
584
+ "Add": self._handle_binop_Add,
585
+ "AddF": self._handle_binop_AddF,
586
+ "AddV": self._handle_binop_AddV,
587
+ "Sub": self._handle_binop_Sub,
588
+ "SubF": self._handle_binop_SubF,
589
+ "SubV": self._handle_binop_SubV,
590
+ "Mul": self._handle_binop_Mul,
591
+ "Mull": self._handle_binop_Mull,
592
+ "MulF": self._handle_binop_MulF,
593
+ "MulV": self._handle_binop_MulV,
594
+ "MulHiV": self._handle_binop_MulHiV,
595
+ "Div": self._handle_binop_Div,
596
+ "DivF": self._handle_binop_DivF,
597
+ "DivV": self._handle_binop_DivV,
598
+ "Mod": self._handle_binop_Mod,
599
+ "Xor": self._handle_binop_Xor,
600
+ "And": self._handle_binop_And,
601
+ "LogicalAnd": self._handle_binop_LogicalAnd,
602
+ "Or": self._handle_binop_Or,
603
+ "LogicalOr": self._handle_binop_LogicalOr,
604
+ "Shl": self._handle_binop_Shl,
605
+ "Shr": self._handle_binop_Shr,
606
+ "Sar": self._handle_binop_Sar,
607
+ "CmpF": self._handle_binop_CmpF,
608
+ "CmpEQ": self._handle_binop_CmpEQ,
609
+ "CmpNE": self._handle_binop_CmpNE,
610
+ "CmpLT": self._handle_binop_CmpLT,
611
+ "CmpLE": self._handle_binop_CmpLE,
612
+ "CmpGT": self._handle_binop_CmpGT,
613
+ "CmpGE": self._handle_binop_CmpGE,
614
+ "Concat": self._handle_binop_Concat,
615
+ "Ror": self._handle_binop_Ror,
616
+ "Rol": self._handle_binop_Rol,
617
+ "Carry": self._handle_binop_Carry,
618
+ "SCarry": self._handle_binop_SCarry,
619
+ "SBorrow": self._handle_binop_SBorrow,
620
+ "InterleaveLOV": self._handle_binop_InterleaveLOV,
621
+ "InterleaveHIV": self._handle_binop_InterleaveHIV,
622
+ "CasCmpEQ": self._handle_binop_CasCmpEQ,
623
+ "CasCmpNE": self._handle_binop_CasCmpNE,
624
+ "ExpCmpNE": self._handle_binop_ExpCmpNE,
625
+ "SarNV": self._handle_binop_SarNV,
626
+ "ShrNV": self._handle_binop_ShrNV,
627
+ "ShlNV": self._handle_binop_ShlNV,
628
+ "CmpEQV": self._handle_binop_CmpEQV,
629
+ "CmpNEV": self._handle_binop_CmpNEV,
630
+ "CmpGEV": self._handle_binop_CmpGEV,
631
+ "CmpGTV": self._handle_binop_CmpGTV,
632
+ "CmpLEV": self._handle_binop_CmpLTV,
633
+ "CmpLTV": self._handle_binop_CmpLEV,
634
+ "MinV": self._handle_binop_MinV,
635
+ "MaxV": self._handle_binop_MaxV,
636
+ "QAddV": self._handle_binop_QAddV,
637
+ "QNarrowBinV": self._handle_binop_QNarrowBinV,
638
+ "PermV": self._handle_binop_PermV,
639
+ "Set": self._handle_binop_Set,
640
+ }
641
+ super().__init__(*args, **kwargs)
436
642
 
437
- def _handle_CCall(self, expr): # pylint:disable=useless-return
438
- if self.l is not None:
439
- self.l.warning("Unsupported expression type CCall with callee %s.", str(expr.cee))
440
- return
643
+ def _process(
644
+ self, state: StateType, *, block: ailment.Block | None = None, whitelist: set[int] | None = None, **kwargs
645
+ ) -> ResultType:
646
+ self.tmps = {}
647
+ if block is None:
648
+ block = self.lift(state)
649
+ self.block = block
650
+ self.state = state
651
+ self.stmt_idx = 0
652
+ self.ins_addr = 0
653
+
654
+ stmt_data = self._process_stmts(whitelist=whitelist)
655
+ result = self._process_block_end(block, stmt_data, whitelist)
656
+ del self.tmps
657
+ del self.block
658
+ del self.state
659
+ del self.stmt_idx
660
+ del self.ins_addr
661
+ return result
662
+
663
+ @abstractmethod
664
+ def _process_block_end(
665
+ self, block: ailment.Block, stmt_data: list[StmtDataType], whitelist: set[int] | None
666
+ ) -> ResultType: ...
441
667
 
442
668
  #
443
- # Unary operation handlers
669
+ # Helper methods
444
670
  #
445
671
 
446
- def _handle_U64(self, expr):
447
- return claripy.BVV(expr.value, 64)
672
+ def _codeloc(self, block_only=False, context=None):
673
+ return CodeLocation(
674
+ self.block.addr,
675
+ None if block_only else self.stmt_idx,
676
+ ins_addr=None if block_only else self.ins_addr,
677
+ context=context,
678
+ block_idx=self.block.idx,
679
+ )
448
680
 
449
- def _handle_U32(self, expr):
450
- return claripy.BVV(expr.value, 32)
681
+ #
682
+ # Statements
683
+ #
451
684
 
452
- def _handle_U16(self, expr):
453
- return claripy.BVV(expr.value, 16)
685
+ def _process_stmts(self, whitelist: set[int] | None) -> list[StmtDataType]:
686
+ result = []
454
687
 
455
- def _handle_U8(self, expr):
456
- return claripy.BVV(expr.value, 8)
688
+ for stmt_idx, stmt in enumerate(self.block.statements):
689
+ if whitelist is not None and stmt_idx not in whitelist:
690
+ continue
691
+
692
+ self.stmt_idx = stmt_idx
693
+ self.ins_addr = stmt.ins_addr
694
+ result.append(self._stmt(stmt))
695
+
696
+ return result
697
+
698
+ def _stmt(self, stmt: ailment.statement.Statement) -> StmtDataType:
699
+ stmt_type_name = type(stmt).__name__
700
+ return self._stmt_handlers[stmt_type_name](stmt)
457
701
 
458
- def _handle_U1(self, expr):
459
- return claripy.BVV(expr.value, 1)
702
+ @abstractmethod
703
+ def _handle_stmt_Assignment(self, stmt: ailment.statement.Assignment) -> StmtDataType: ...
460
704
 
461
- def _handle_Const(self, expr): # pylint:disable=no-self-use
462
- return claripy_value(expr.con.type, expr.con.value)
705
+ @abstractmethod
706
+ def _handle_stmt_Store(self, stmt: ailment.statement.Store) -> StmtDataType: ...
463
707
 
464
- def _handle_Conversion(self, expr):
465
- expr_ = self._expr(expr.args[0])
466
- if expr_ is None:
467
- return None
468
- to_size = expr.result_size(self.tyenv)
469
- if self._is_top(expr_):
470
- return self._top(to_size)
708
+ @abstractmethod
709
+ def _handle_stmt_Jump(self, stmt: ailment.statement.Jump) -> StmtDataType: ...
471
710
 
472
- if isinstance(expr_, claripy.ast.Base) and expr_.op == "BVV":
473
- if expr_.size() > to_size:
474
- # truncation
475
- return expr_[to_size - 1 : 0]
476
- if expr_.size() < to_size:
477
- # extension
478
- return claripy.ZeroExt(to_size - expr_.size(), expr_)
479
- return expr_
711
+ @abstractmethod
712
+ def _handle_stmt_ConditionalJump(self, stmt: ailment.statement.ConditionalJump) -> StmtDataType: ...
480
713
 
481
- return self._top(to_size)
714
+ @abstractmethod
715
+ def _handle_stmt_Call(self, stmt: ailment.statement.Call) -> StmtDataType: ...
716
+
717
+ @abstractmethod
718
+ def _handle_stmt_Return(self, stmt: ailment.statement.Return) -> StmtDataType: ...
719
+
720
+ @abstractmethod
721
+ def _handle_stmt_DirtyStatement(self, stmt: ailment.statement.DirtyStatement) -> StmtDataType: ...
722
+
723
+ @abstractmethod
724
+ def _handle_stmt_Label(self, stmt: ailment.statement.Label) -> StmtDataType: ...
482
725
 
483
726
  #
484
- # Binary operation handlers
727
+ # Expressions
485
728
  #
486
729
 
487
- def _binop_get_args(self, expr) -> tuple[Any, Any] | None | Any | None:
488
- arg0, arg1 = expr.args
489
- expr_0 = self._expr(arg0)
490
- if expr_0 is None:
491
- return None, None
492
- if self._is_top(expr_0):
493
- return None, self._top(expr_0.size())
730
+ def _expr(self, expr: ailment.Expression) -> DataType_co:
731
+ expr_type_name = type(expr).__name__
732
+ return self._expr_handlers[expr_type_name](expr)
494
733
 
495
- expr_1 = self._expr(arg1)
496
- if expr_1 is None:
497
- return None, None
498
- if self._is_top(expr_1):
499
- return None, self._top(expr_0.size()) # always use the size of expr_0
734
+ def _handle_expr_Atom(self, expr: ailment.expression.Atom) -> DataType_co:
735
+ raise TypeError("We should never see raw Atoms")
500
736
 
501
- return (expr_0, expr_1), None
737
+ @abstractmethod
738
+ def _handle_expr_Const(self, expr: ailment.expression.Const) -> DataType_co: ...
502
739
 
503
- def _handle_And(self, expr):
504
- args, r = self._binop_get_args(expr)
505
- if args is None:
506
- return r
507
- expr_0, expr_1 = args
740
+ @abstractmethod
741
+ def _handle_expr_Tmp(self, expr: ailment.expression.Tmp) -> DataType_co: ...
508
742
 
509
- if self._is_top(expr_0) or self._is_top(expr_1):
510
- return self._top(expr_0.size())
743
+ @abstractmethod
744
+ def _handle_expr_VirtualVariable(self, expr: ailment.expression.VirtualVariable) -> DataType_co: ...
511
745
 
512
- return expr_0 & expr_1
746
+ @abstractmethod
747
+ def _handle_expr_Phi(self, expr: ailment.expression.Phi) -> DataType_co: ...
513
748
 
514
- def _handle_Or(self, expr):
515
- args, r = self._binop_get_args(expr)
516
- if args is None:
517
- return r
518
- expr_0, expr_1 = args
749
+ def _handle_expr_Op(self, expr: ailment.expression.Op) -> DataType_co:
750
+ raise TypeError("We should never see raw Ops")
519
751
 
520
- if self._is_top(expr_0) or self._is_top(expr_1):
521
- return self._top(expr_0.size())
752
+ def _handle_expr_UnaryOp(self, expr: ailment.expression.UnaryOp) -> DataType_co:
753
+ return self._unop_handlers[expr.op](expr)
522
754
 
523
- return expr_0 | expr_1
755
+ def _handle_expr_BinaryOp(self, expr: ailment.expression.BinaryOp) -> DataType_co:
756
+ return self._binop_handlers[expr.op](expr)
524
757
 
525
- def _handle_Not1(self, expr):
526
- return self._handle_Not(expr)
758
+ @abstractmethod
759
+ def _handle_expr_Convert(self, expr: ailment.expression.Convert) -> DataType_co: ...
527
760
 
528
- def _handle_Not(self, expr):
529
- arg0 = expr.args[0]
530
- expr_0 = self._expr(arg0)
531
- if expr_0 is None:
532
- return None
533
- if self._is_top(expr_0):
534
- return self._top(expr_0.size())
761
+ @abstractmethod
762
+ def _handle_expr_Reinterpret(self, expr: ailment.expression.Reinterpret) -> DataType_co: ...
535
763
 
536
- try:
537
- return ~expr_0 # pylint:disable=invalid-unary-operand-type
538
- except TypeError as e:
539
- if self.l is not None:
540
- self.l.exception(e)
541
- return None
542
-
543
- def _handle_Clz(self, expr):
544
- arg0 = expr.args[0]
545
- expr_0 = self._expr(arg0)
546
- if expr_0 is None:
547
- return None
548
- if self._is_top(expr_0):
549
- return self._top(expr_0.size())
550
- return self._top(expr_0.size())
551
-
552
- def _handle_Ctz(self, expr):
553
- arg0 = expr.args[0]
554
- expr_0 = self._expr(arg0)
555
- if expr_0 is None:
556
- return None
557
- if self._is_top(expr_0):
558
- return self._top(expr_0.size())
559
- return self._top(expr_0.size())
560
-
561
- def _handle_Add(self, expr):
562
- args, r = self._binop_get_args(expr)
563
- if args is None:
564
- return r
565
- expr_0, expr_1 = args
566
-
567
- if self._is_top(expr_0) or self._is_top(expr_1):
568
- return self._top(expr_0.size())
569
-
570
- return expr_0 + expr_1
571
-
572
- def _handle_Sub(self, expr):
573
- args, r = self._binop_get_args(expr)
574
- if args is None:
575
- return r
576
- expr_0, expr_1 = args
577
-
578
- if self._is_top(expr_0) or self._is_top(expr_1):
579
- return self._top(expr_0.size())
580
-
581
- return expr_0 - expr_1
582
-
583
- def _handle_Mul(self, expr):
584
- args, r = self._binop_get_args(expr)
585
- if args is None:
586
- return r
587
- expr_0, expr_1 = args
588
-
589
- if self._is_top(expr_0) or self._is_top(expr_1):
590
- return self._top(expr_0.size())
591
-
592
- return expr_0 * expr_1
593
-
594
- def _handle_Mull(self, expr):
595
- self._binop_get_args(expr)
596
- return self._top(expr.result_size(self.tyenv))
597
-
598
- def _handle_DivMod(self, expr):
599
- args, r = self._binop_get_args(expr)
600
- if args is None:
601
- return r
602
- expr_0, expr_1 = args
603
-
604
- if self._is_top(expr_0) or self._is_top(expr_1):
605
- return self._top(expr.result_size(self.tyenv))
606
-
607
- if expr_1.concrete and expr_1.concrete_value == 0:
608
- return self._top(expr.result_size(self.tyenv))
609
-
610
- signed = "U" in expr.op # Iop_DivModU64to32 vs Iop_DivMod
611
- from_size = expr_0.size()
612
- to_size = expr_1.size()
613
- if signed:
614
- quotient = expr_0.SDiv(claripy.SignExt(from_size - to_size, expr_1))
615
- remainder = expr_0.SMod(claripy.SignExt(from_size - to_size, expr_1))
616
- quotient_size = to_size
617
- remainder_size = to_size
618
- return claripy.Concat(
619
- claripy.Extract(remainder_size - 1, 0, remainder), claripy.Extract(quotient_size - 1, 0, quotient)
620
- )
621
- quotient = expr_0 // claripy.ZeroExt(from_size - to_size, expr_1)
622
- remainder = expr_0 % claripy.ZeroExt(from_size - to_size, expr_1)
623
- quotient_size = to_size
624
- remainder_size = to_size
625
- return claripy.Concat(
626
- claripy.Extract(remainder_size - 1, 0, remainder), claripy.Extract(quotient_size - 1, 0, quotient)
627
- )
764
+ @abstractmethod
765
+ def _handle_expr_Load(self, expr: ailment.expression.Load) -> DataType_co: ...
628
766
 
629
- def _handle_Div(self, expr):
630
- args, r = self._binop_get_args(expr)
631
- if args is None:
632
- return r
633
- expr_0, expr_1 = args
767
+ @abstractmethod
768
+ def _handle_expr_Register(self, expr: ailment.expression.Register) -> DataType_co: ...
634
769
 
635
- if self._is_top(expr_0) or self._is_top(expr_1):
636
- return self._top(expr_0.size())
770
+ @abstractmethod
771
+ def _handle_expr_ITE(self, expr: ailment.expression.ITE) -> DataType_co: ...
637
772
 
638
- if expr_1.concrete and expr_1.concrete_value == 0:
639
- return self._top(expr.result_size(self.tyenv))
773
+ @abstractmethod
774
+ def _handle_expr_Call(self, expr: ailment.statement.Call) -> DataType_co: ...
640
775
 
641
- try:
642
- return expr_0 / expr_1
643
- except ZeroDivisionError:
644
- return self._top(expr.result_size(self.tyenv))
776
+ @abstractmethod
777
+ def _handle_expr_DirtyExpression(self, expr: ailment.expression.DirtyExpression) -> DataType_co: ...
645
778
 
646
- def _handle_Mod(self, expr):
647
- args, r = self._binop_get_args(expr)
648
- if args is None:
649
- return r
650
- expr_0, expr_1 = args
779
+ @abstractmethod
780
+ def _handle_expr_VEXCCallExpression(self, expr: ailment.expression.VEXCCallExpression) -> DataType_co: ...
651
781
 
652
- if self._is_top(expr_0) or self._is_top(expr_1):
653
- return self._top(expr_0.size())
782
+ @abstractmethod
783
+ def _handle_expr_MultiStatementExpression(
784
+ self, expr: ailment.expression.MultiStatementExpression
785
+ ) -> DataType_co: ...
654
786
 
655
- if expr_1.concrete and expr_1.concrete_value == 0:
656
- return self._top(expr.result_size(self.tyenv))
787
+ @abstractmethod
788
+ def _handle_expr_BasePointerOffset(self, expr: ailment.expression.BasePointerOffset) -> DataType_co: ...
657
789
 
658
- try:
659
- return expr_0 - (expr_1 // expr_1) * expr_1
660
- except ZeroDivisionError:
661
- return self._top(expr_0.size())
790
+ @abstractmethod
791
+ def _handle_expr_StackBaseOffset(self, expr: ailment.expression.StackBaseOffset) -> DataType_co: ...
662
792
 
663
- def _handle_Xor(self, expr):
664
- args, r = self._binop_get_args(expr)
665
- if args is None:
666
- return r
667
- expr_0, expr_1 = args
793
+ #
794
+ # UnOps
795
+ #
668
796
 
669
- if self._is_top(expr_0) or self._is_top(expr_1):
670
- return self._top(expr_0.size())
797
+ @abstractmethod
798
+ def _handle_unop_Not(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
671
799
 
672
- try:
673
- return expr_0 ^ expr_1
674
- except TypeError as e:
675
- if self.l is not None:
676
- self.l.warning(e)
677
- return None
678
-
679
- def _handle_Shl(self, expr):
680
- args, r = self._binop_get_args(expr)
681
- if args is None:
682
- return r
683
- expr_0, expr_1 = args
684
-
685
- if self._is_top(expr_0) or self._is_top(expr_1):
686
- return self._top(expr_0.size())
687
-
688
- if isinstance(expr_1, claripy.ast.Base) and expr_1.op == "BVV":
689
- # convert it to an int when possible
690
- expr_1 = expr_1.args[0]
691
- else:
692
- # make sure the sizes are the same - VEX does not care about it
693
- if expr_1.size() < expr_0.size():
694
- expr_1 = claripy.ZeroExt(expr_0.size() - expr_1.size(), expr_1)
695
- elif expr_1.size() > expr_0.size():
696
- expr_1 = claripy.Extract(expr_0.size() - 1, 0, expr_1)
697
-
698
- return expr_0 << expr_1
699
-
700
- def _handle_Shr(self, expr):
701
- args, r = self._binop_get_args(expr)
702
- if args is None:
703
- return r
704
- expr_0, expr_1 = args
705
-
706
- if self._is_top(expr_0) or self._is_top(expr_1):
707
- return self._top(expr_0.size())
708
-
709
- if isinstance(expr_1, claripy.ast.Base) and expr_1.op == "BVV":
710
- # convert it to an int when possible
711
- expr_1 = expr_1.args[0]
712
- else:
713
- # make sure the sizes are the same - VEX does not care about it
714
- if expr_1.size() < expr_0.size():
715
- expr_1 = claripy.ZeroExt(expr_0.size() - expr_1.size(), expr_1)
716
- elif expr_1.size() > expr_0.size():
717
- expr_1 = claripy.Extract(expr_0.size() - 1, 0, expr_1)
718
-
719
- return claripy.LShR(expr_0, expr_1)
720
-
721
- def _handle_Sar(self, expr):
722
- # EDG asks: is this right?
723
- args, r = self._binop_get_args(expr)
724
- if args is None:
725
- return r
726
- expr_0, expr_1 = args
727
-
728
- if self._is_top(expr_0) or self._is_top(expr_1):
729
- return self._top(expr_0.size())
730
-
731
- if isinstance(expr_1, claripy.ast.Base) and expr_1.op == "BVV":
732
- # convert it to an int when possible
733
- expr_1 = expr_1.args[0]
734
- else:
735
- # make sure the sizes are the same - VEX does not care about it
736
- if expr_1.size() < expr_0.size():
737
- expr_1 = claripy.ZeroExt(expr_0.size() - expr_1.size(), expr_1)
738
- elif expr_1.size() > expr_0.size():
739
- expr_1 = claripy.Extract(expr_0.size() - 1, 0, expr_1)
740
-
741
- return expr_0 >> expr_1
742
-
743
- def _handle_CmpEQ(self, expr):
744
- args, r = self._binop_get_args(expr)
745
- if args is None:
746
- return r
747
- expr_0, expr_1 = args
748
-
749
- if self._is_top(expr_0) or self._is_top(expr_1):
750
- return self._top(1)
751
-
752
- return expr_0 == expr_1
753
-
754
- def _handle_CmpNE(self, expr):
755
- args, r = self._binop_get_args(expr)
756
- if args is None:
757
- return r
758
- expr_0, expr_1 = args
759
-
760
- if self._is_top(expr_0) or self._is_top(expr_1):
761
- return self._top(1)
762
-
763
- return expr_0 != expr_1
764
-
765
- def _handle_CmpLE(self, expr):
766
- args, r = self._binop_get_args(expr)
767
- if args is None:
768
- return r
769
- expr_0, expr_1 = args
770
-
771
- if self._is_top(expr_0) or self._is_top(expr_1):
772
- return self._top(1)
773
-
774
- return expr_0 <= expr_1
775
-
776
- def _handle_CmpGE(self, expr):
777
- args, r = self._binop_get_args(expr)
778
- if args is None:
779
- return r
780
- expr_0, expr_1 = args
781
-
782
- if self._is_top(expr_0) or self._is_top(expr_1):
783
- return self._top(1)
784
-
785
- return expr_0 >= expr_1
786
-
787
- def _handle_CmpLT(self, expr):
788
- args, r = self._binop_get_args(expr)
789
- if args is None:
790
- return r
791
- expr_0, expr_1 = args
792
-
793
- if self._is_top(expr_0) or self._is_top(expr_1):
794
- return self._top(1)
795
-
796
- return expr_0 < expr_1
800
+ @abstractmethod
801
+ def _handle_unop_Neg(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
797
802
 
798
- def _handle_CmpGT(self, expr):
799
- args, r = self._binop_get_args(expr)
800
- if args is None:
801
- return r
802
- expr_0, expr_1 = args
803
-
804
- if self._is_top(expr_0) or self._is_top(expr_1):
805
- return self._top(1)
806
-
807
- return expr_0 > expr_1
803
+ @abstractmethod
804
+ def _handle_unop_BitwiseNeg(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
808
805
 
809
- def _handle_CmpEQ_v(self, expr, _vector_size, _vector_count):
810
- _, _ = self._binop_get_args(expr)
811
- return self._top(expr.result_size(self.tyenv))
806
+ @abstractmethod
807
+ def _handle_unop_Reference(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
812
808
 
813
- def _handle_CmpNE_v(self, expr, _vector_size, _vector_count):
814
- _, _ = self._binop_get_args(expr)
815
- return self._top(expr.result_size(self.tyenv))
809
+ @abstractmethod
810
+ def _handle_unop_Dereference(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
816
811
 
817
- def _handle_CmpLE_v(self, expr, _vector_size, _vector_count):
818
- _, _ = self._binop_get_args(expr)
819
- return self._top(expr.result_size(self.tyenv))
812
+ @abstractmethod
813
+ def _handle_unop_Clz(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
820
814
 
821
- def _handle_CmpGE_v(self, expr, _vector_size, _vector_count):
822
- _, _ = self._binop_get_args(expr)
823
- return self._top(expr.result_size(self.tyenv))
815
+ @abstractmethod
816
+ def _handle_unop_Ctz(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
824
817
 
825
- def _handle_CmpLT_v(self, expr, _vector_size, _vector_count):
826
- _, _ = self._binop_get_args(expr)
827
- return self._top(expr.result_size(self.tyenv))
818
+ @abstractmethod
819
+ def _handle_unop_GetMSBs(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
828
820
 
829
- def _handle_CmpGT_v(self, expr, _vector_size, _vector_count):
830
- _, _ = self._binop_get_args(expr)
831
- return self._top(expr.result_size(self.tyenv))
821
+ @abstractmethod
822
+ def _handle_unop_unpack(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
832
823
 
833
- def _handle_MBE(self, _expr: pyvex.IRStmt.MBE):
834
- # Yeah.... no.
835
- return None
824
+ @abstractmethod
825
+ def _handle_unop_Sqrt(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
836
826
 
837
- def _handle_32HLto64(self, expr):
838
- args, r = self._binop_get_args(expr)
839
- if args is None:
840
- if r is not None:
841
- # the size of r should be 32 but we need to return a 64-bit expression
842
- assert r.size() == 32
843
- r = claripy.ZeroExt(32, r)
844
- return r
827
+ @abstractmethod
828
+ def _handle_unop_RSqrtEst(self, expr: ailment.expression.UnaryOp) -> DataType_co: ...
845
829
 
846
- return None
830
+ #
831
+ # BinOps
832
+ #
833
+ @abstractmethod
834
+ def _handle_binop_Add(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
847
835
 
848
- def _handle_16HLto32(self, expr):
849
- _, _ = self._binop_get_args(expr)
850
- return self._top(expr.result_size(self.tyenv))
836
+ @abstractmethod
837
+ def _handle_binop_AddF(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
851
838
 
852
- def _handle_ExpCmpNE64(self, expr):
853
- _, _ = self._expr(expr.args[0]), self._expr(expr.args[1])
854
- return self._top(expr.result_size(self.tyenv))
839
+ @abstractmethod
840
+ def _handle_binop_AddV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
855
841
 
842
+ @abstractmethod
843
+ def _handle_binop_Sub(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
856
844
 
857
- # noinspection PyPep8Naming
858
- class SimEngineLightAILMixin(SimEngineLightMixin):
845
+ @abstractmethod
846
+ def _handle_binop_SubF(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
847
+
848
+ @abstractmethod
849
+ def _handle_binop_SubV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
850
+
851
+ @abstractmethod
852
+ def _handle_binop_Mul(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
853
+
854
+ @abstractmethod
855
+ def _handle_binop_Mull(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
856
+
857
+ @abstractmethod
858
+ def _handle_binop_MulF(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
859
+
860
+ @abstractmethod
861
+ def _handle_binop_MulV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
862
+
863
+ @abstractmethod
864
+ def _handle_binop_MulHiV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
865
+
866
+ @abstractmethod
867
+ def _handle_binop_Div(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
868
+
869
+ @abstractmethod
870
+ def _handle_binop_DivF(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
871
+
872
+ @abstractmethod
873
+ def _handle_binop_DivV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
874
+
875
+ @abstractmethod
876
+ def _handle_binop_Mod(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
877
+
878
+ @abstractmethod
879
+ def _handle_binop_Xor(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
880
+
881
+ @abstractmethod
882
+ def _handle_binop_And(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
883
+
884
+ @abstractmethod
885
+ def _handle_binop_LogicalAnd(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
886
+
887
+ @abstractmethod
888
+ def _handle_binop_Or(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
889
+
890
+ @abstractmethod
891
+ def _handle_binop_LogicalOr(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
892
+
893
+ @abstractmethod
894
+ def _handle_binop_Shl(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
895
+
896
+ @abstractmethod
897
+ def _handle_binop_Shr(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
898
+
899
+ @abstractmethod
900
+ def _handle_binop_Sar(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
901
+
902
+ @abstractmethod
903
+ def _handle_binop_CmpF(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
904
+
905
+ @abstractmethod
906
+ def _handle_binop_CmpEQ(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
907
+
908
+ @abstractmethod
909
+ def _handle_binop_CmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
910
+
911
+ @abstractmethod
912
+ def _handle_binop_CmpLT(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
913
+
914
+ @abstractmethod
915
+ def _handle_binop_CmpLE(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
916
+
917
+ @abstractmethod
918
+ def _handle_binop_CmpGT(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
919
+
920
+ @abstractmethod
921
+ def _handle_binop_CmpGE(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
922
+
923
+ @abstractmethod
924
+ def _handle_binop_Concat(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
925
+
926
+ @abstractmethod
927
+ def _handle_binop_Ror(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
928
+
929
+ @abstractmethod
930
+ def _handle_binop_Rol(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
931
+
932
+ @abstractmethod
933
+ def _handle_binop_Carry(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
934
+
935
+ @abstractmethod
936
+ def _handle_binop_SCarry(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
937
+
938
+ @abstractmethod
939
+ def _handle_binop_SBorrow(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
940
+
941
+ @abstractmethod
942
+ def _handle_binop_InterleaveLOV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
943
+
944
+ @abstractmethod
945
+ def _handle_binop_InterleaveHIV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
946
+
947
+ @abstractmethod
948
+ def _handle_binop_CasCmpEQ(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
949
+
950
+ @abstractmethod
951
+ def _handle_binop_CasCmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
952
+
953
+ @abstractmethod
954
+ def _handle_binop_ExpCmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
955
+
956
+ @abstractmethod
957
+ def _handle_binop_SarNV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
958
+
959
+ @abstractmethod
960
+ def _handle_binop_ShrNV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
961
+
962
+ @abstractmethod
963
+ def _handle_binop_ShlNV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
964
+
965
+ @abstractmethod
966
+ def _handle_binop_CmpEQV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
967
+
968
+ @abstractmethod
969
+ def _handle_binop_CmpNEV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
970
+
971
+ @abstractmethod
972
+ def _handle_binop_CmpGEV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
973
+
974
+ @abstractmethod
975
+ def _handle_binop_CmpGTV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
976
+
977
+ @abstractmethod
978
+ def _handle_binop_CmpLEV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
979
+
980
+ @abstractmethod
981
+ def _handle_binop_CmpLTV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
982
+
983
+ @abstractmethod
984
+ def _handle_binop_MinV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
985
+
986
+ @abstractmethod
987
+ def _handle_binop_MaxV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
988
+
989
+ @abstractmethod
990
+ def _handle_binop_QAddV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
991
+
992
+ @abstractmethod
993
+ def _handle_binop_QNarrowBinV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
994
+
995
+ @abstractmethod
996
+ def _handle_binop_PermV(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
997
+
998
+ @abstractmethod
999
+ def _handle_binop_Set(self, expr: ailment.expression.BinaryOp) -> DataType_co: ...
1000
+
1001
+
1002
+ class SimEngineNostmtAIL(
1003
+ Generic[StateType, DataType_co, StmtDataType, ResultType],
1004
+ SimEngineLightAIL[StateType, DataType_co, StmtDataType | None, ResultType],
1005
+ ):
859
1006
  """
860
- A mixin for doing static analysis on AIL
1007
+ A base class of SimEngineLightAIL that has default handlers for statements if they just need to return None, so you
1008
+ don't have to implement every single statement handler as ``return None``.
861
1009
  """
862
1010
 
863
- def _process(
864
- self, state, successors, *args, block=None, whitelist=None, **kwargs
865
- ): # pylint:disable=arguments-differ
866
- self.tmps = {}
867
- self.block: ailment.Block = block
868
- self.state = state
869
- if self.arch is None:
870
- # we only access state.arch if the arch of this engine itself is not previously configured
871
- self.arch = state.arch
1011
+ def _handle_stmt_Assignment(self, stmt) -> StmtDataType | None:
1012
+ pass
872
1013
 
873
- self._process_Stmt(whitelist=whitelist)
1014
+ def _handle_stmt_Store(self, stmt) -> StmtDataType | None:
1015
+ pass
874
1016
 
875
- self.stmt_idx = None
876
- self.ins_addr = None
1017
+ def _handle_stmt_Jump(self, stmt) -> StmtDataType | None:
1018
+ pass
877
1019
 
878
- def _process_Stmt(self, whitelist=None):
879
- if whitelist is not None:
880
- whitelist = set(whitelist)
1020
+ def _handle_stmt_ConditionalJump(self, stmt) -> StmtDataType | None:
1021
+ pass
881
1022
 
882
- for stmt_idx, stmt in enumerate(self.block.statements):
883
- if whitelist is not None and stmt_idx not in whitelist:
884
- continue
1023
+ def _handle_stmt_Call(self, stmt) -> StmtDataType | None:
1024
+ pass
885
1025
 
886
- self.stmt_idx = stmt_idx
887
- self.ins_addr = stmt.ins_addr
1026
+ def _handle_stmt_Return(self, stmt) -> StmtDataType | None:
1027
+ pass
888
1028
 
889
- self._handle_Stmt(stmt)
1029
+ def _handle_stmt_DirtyStatement(self, stmt) -> StmtDataType | None:
1030
+ pass
890
1031
 
891
- def _expr(self, expr):
892
- expr_type_name = type(expr).__name__
893
- if isinstance(expr, ailment.Stmt.Call):
894
- # Call can be both an expression and a statement. Add a suffix to make sure we are working on the expression
895
- # variant.
896
- expr_type_name += "Expr"
897
-
898
- h = None
899
- handler = f"_handle_{expr_type_name}"
900
- if hasattr(self, handler):
901
- h = getattr(self, handler)
902
-
903
- if h is None:
904
- handler = f"_ail_handle_{expr_type_name}"
905
- if hasattr(self, handler):
906
- h = getattr(self, handler)
907
-
908
- if h is not None:
909
- return h(expr)
910
- if self.l is not None:
911
- self.l.warning("Unsupported expression type %s.", type(expr).__name__)
912
- return None
1032
+ def _handle_stmt_Label(self, stmt) -> StmtDataType | None:
1033
+ pass
913
1034
 
914
- #
915
- # Helper methods
916
- #
917
1035
 
918
- def _codeloc(self, block_only=False, context=None):
919
- return CodeLocation(
920
- self.block.addr,
921
- None if block_only else self.stmt_idx,
922
- ins_addr=None if block_only else self.ins_addr,
923
- context=context,
924
- block_idx=self.block.idx,
925
- )
1036
+ class SimEngineNoexprAIL(
1037
+ Generic[StateType, DataType_co, StmtDataType, ResultType],
1038
+ SimEngineLightAIL[StateType, DataType_co | None, StmtDataType, ResultType],
1039
+ ):
1040
+ """
1041
+ A base class of SimEngineLightAIL that has default handlers for expressions if they just need to return None, so you
1042
+ don't have to implement every single expression handler as ``return None``.
1043
+ """
926
1044
 
927
- #
928
- # Statement handlers
929
- #
1045
+ def _handle_expr_Atom(self, expr: ailment.expression.Atom) -> DataType_co | None:
1046
+ pass
930
1047
 
931
- def _handle_Stmt(self, stmt):
932
- handler = f"_handle_{type(stmt).__name__}"
933
- if hasattr(self, handler):
934
- return getattr(self, handler)(stmt)
1048
+ def _handle_expr_Const(self, expr: ailment.expression.Const) -> DataType_co | None:
1049
+ pass
935
1050
 
936
- # compatibility
937
- old_handler = f"_ail_handle_{type(stmt).__name__}"
938
- if hasattr(self, old_handler):
939
- return getattr(self, old_handler)(stmt)
1051
+ def _handle_expr_Tmp(self, expr: ailment.expression.Tmp) -> DataType_co | None:
1052
+ pass
940
1053
 
941
- if self.l is not None:
942
- self.l.warning("Unsupported statement type %s.", type(stmt).__name__)
943
- return None
1054
+ def _handle_expr_VirtualVariable(self, expr: ailment.expression.VirtualVariable) -> DataType_co | None:
1055
+ pass
1056
+
1057
+ def _handle_expr_Phi(self, expr: ailment.expression.Phi) -> DataType_co | None:
1058
+ pass
944
1059
 
945
- def _ail_handle_Assignment(self, stmt):
1060
+ def _handle_expr_Convert(self, expr: ailment.expression.Convert) -> DataType_co | None:
946
1061
  pass
947
1062
 
948
- def _ail_handle_Label(self, stmt):
1063
+ def _handle_expr_Reinterpret(self, expr: ailment.expression.Reinterpret) -> DataType_co | None:
949
1064
  pass
950
1065
 
951
- def _ail_handle_Jump(self, stmt):
1066
+ def _handle_expr_Load(self, expr: ailment.expression.Load) -> DataType_co | None:
952
1067
  pass
953
1068
 
954
- def _ail_handle_Call(self, stmt):
1069
+ def _handle_expr_Register(self, expr: ailment.expression.Register) -> DataType_co | None:
955
1070
  pass
956
1071
 
957
- def _ail_handle_Return(self, stmt):
1072
+ def _handle_expr_ITE(self, expr: ailment.expression.ITE) -> DataType_co | None:
958
1073
  pass
959
1074
 
960
- def _ail_handle_DirtyStatement(self, stmt):
961
- self._expr(stmt.dirty)
1075
+ def _handle_expr_Call(self, expr: ailment.statement.Call) -> DataType_co | None:
1076
+ pass
962
1077
 
963
- #
964
- # Expression handlers
965
- #
1078
+ def _handle_expr_DirtyExpression(self, expr: ailment.expression.DirtyExpression) -> DataType_co | None:
1079
+ pass
966
1080
 
967
- def _ail_handle_BV(self, expr: claripy.ast.Base):
968
- return expr
1081
+ def _handle_expr_VEXCCallExpression(self, expr: ailment.expression.VEXCCallExpression) -> DataType_co | None:
1082
+ pass
969
1083
 
970
- def _ail_handle_Const(self, expr): # pylint:disable=no-self-use
971
- return expr.value
1084
+ def _handle_expr_MultiStatementExpression(
1085
+ self, expr: ailment.expression.MultiStatementExpression
1086
+ ) -> DataType_co | None:
1087
+ pass
972
1088
 
973
- def _ail_handle_StackBaseOffset(self, expr: ailment.Expr.StackBaseOffset):
974
- return expr
1089
+ def _handle_expr_BasePointerOffset(self, expr: ailment.expression.BasePointerOffset) -> DataType_co | None:
1090
+ pass
975
1091
 
976
- def _ail_handle_Tmp(self, expr):
977
- tmp_idx = expr.tmp_idx
1092
+ def _handle_expr_StackBaseOffset(self, expr: ailment.expression.StackBaseOffset) -> DataType_co | None:
1093
+ pass
978
1094
 
979
- try:
980
- return self.tmps[tmp_idx]
981
- except KeyError:
982
- return None
983
-
984
- def _ail_handle_Load(self, expr: ailment.Expr.Load):
985
- self._expr(expr.addr)
986
- return expr
987
-
988
- def _ail_handle_CallExpr(self, expr: ailment.Stmt.Call):
989
- if not isinstance(expr.target, str):
990
- self._expr(expr.target)
991
- return expr
992
-
993
- def _ail_handle_Reinterpret(self, expr: ailment.Expr.Reinterpret):
994
- arg = self._expr(expr.operand)
995
-
996
- if isinstance(arg, int) and (
997
- expr.from_bits == 32 and expr.from_type == "I" and expr.to_bits == 32 and expr.to_type == "F"
998
- ):
999
- # int -> float
1000
- b = struct.pack("<I", arg)
1001
- return struct.unpack("<f", b)[0]
1002
- if (
1003
- isinstance(arg, float)
1004
- and expr.from_bits == 32
1005
- and expr.from_type == "F"
1006
- and expr.to_bits == 32
1007
- and expr.to_type == "I"
1008
- ):
1009
- # float -> int
1010
- b = struct.pack("<f", arg)
1011
- return struct.unpack("<I", b)[0]
1012
-
1013
- return expr
1014
-
1015
- def _ail_handle_DirtyExpression(self, expr: ailment.Expr.DirtyExpression):
1016
- for operand in expr.operands:
1017
- self._expr(operand)
1018
- if expr.guard is not None:
1019
- self._expr(expr.guard)
1020
- if expr.maddr is not None:
1021
- self._expr(expr.maddr)
1022
- return expr
1023
-
1024
- def _ail_handle_UnaryOp(self, expr):
1025
- handler_name = f"_handle_{expr.op}"
1026
- try:
1027
- handler = getattr(self, handler_name)
1028
- except AttributeError:
1029
- handler_name = f"_ail_handle_{expr.op}"
1030
- try:
1031
- handler = getattr(self, handler_name)
1032
- except AttributeError:
1033
- if self.l is not None:
1034
- self.l.warning("Unsupported UnaryOp %s.", expr.op)
1035
- return None
1036
-
1037
- return handler(expr)
1038
-
1039
- def _ail_handle_BinaryOp(self, expr):
1040
- handler_name = f"_handle_{expr.op}"
1041
- try:
1042
- handler = getattr(self, handler_name)
1043
- except AttributeError:
1044
- handler_name = f"_ail_handle_{expr.op}"
1045
- try:
1046
- handler = getattr(self, handler_name)
1047
- except AttributeError:
1048
- if self.l is not None:
1049
- self.l.warning("Unsupported BinaryOp %s.", expr.op)
1050
- return None
1051
-
1052
- return handler(expr)
1053
-
1054
- def _ail_handle_TernaryOp(self, expr):
1055
- handler_name = f"_handle_{expr.op}"
1056
- try:
1057
- handler = getattr(self, handler_name)
1058
- except AttributeError:
1059
- handler_name = f"_ail_handle_{expr.op}"
1060
- try:
1061
- handler = getattr(self, handler_name)
1062
- except AttributeError:
1063
- if self.l is not None:
1064
- self.l.warning("Unsupported Ternary %s.", expr.op)
1065
- return None
1066
-
1067
- return handler(expr)
1095
+ def _handle_unop_Not(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1096
+ pass
1068
1097
 
1069
- #
1070
- # Binary operation handlers
1071
- #
1098
+ def _handle_unop_Neg(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1099
+ pass
1072
1100
 
1073
- def _ail_handle_CmpEQ(self, expr):
1074
- arg0, arg1 = expr.operands
1101
+ def _handle_unop_BitwiseNeg(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1102
+ pass
1075
1103
 
1076
- expr_0 = self._expr(arg0)
1077
- expr_1 = self._expr(arg1)
1078
- if expr_0 is None:
1079
- expr_0 = arg0
1080
- if expr_1 is None:
1081
- expr_1 = arg1
1104
+ def _handle_unop_Reference(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1105
+ pass
1082
1106
 
1083
- try:
1084
- if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1085
- if expr_0.value == expr_1.value:
1086
- return ailment.Expr.Const(None, None, 1, 1)
1087
- return ailment.Expr.Const(None, None, 0, 1)
1088
- except TypeError:
1089
- pass
1090
- return ailment.Expr.BinaryOp(expr.idx, "CmpEQ", [expr_0, expr_1], expr.signed, **expr.tags)
1091
-
1092
- def _ail_handle_CmpNE(self, expr):
1093
- arg0, arg1 = expr.operands
1094
-
1095
- expr_0 = self._expr(arg0)
1096
- expr_1 = self._expr(arg1)
1097
- if expr_0 is None:
1098
- expr_0 = arg0
1099
- if expr_1 is None:
1100
- expr_1 = arg1
1107
+ def _handle_unop_Dereference(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1108
+ pass
1101
1109
 
1102
- try:
1103
- if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1104
- if expr_0.value != expr_1.value:
1105
- return ailment.Expr.Const(None, None, 1, 1)
1106
- return ailment.Expr.Const(None, None, 0, 1)
1107
- except TypeError:
1108
- pass
1109
- return ailment.Expr.BinaryOp(expr.idx, "CmpNE", [expr_0, expr_1], expr.signed, **expr.tags)
1110
-
1111
- def _ail_handle_CmpLT(self, expr):
1112
- arg0, arg1 = expr.operands
1113
-
1114
- expr_0 = self._expr(arg0)
1115
- expr_1 = self._expr(arg1)
1116
- if expr_0 is None:
1117
- expr_0 = arg0
1118
- if expr_1 is None:
1119
- expr_1 = arg1
1110
+ def _handle_unop_GetMSBs(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1111
+ pass
1120
1112
 
1121
- try:
1122
- if isinstance(expr_0, ailment.Expr.Const) and isinstance(expr_1, ailment.Expr.Const):
1123
- if expr_0.value < expr_1.value:
1124
- return ailment.Expr.Const(None, None, 1, 1)
1125
- return ailment.Expr.Const(None, None, 0, 1)
1126
- except TypeError:
1127
- pass
1128
- return ailment.Expr.BinaryOp(expr.idx, "CmpLT", [expr_0, expr_1], expr.signed, **expr.tags)
1129
-
1130
- def _ail_handle_Add(self, expr):
1131
- arg0, arg1 = expr.operands
1132
-
1133
- expr_0 = self._expr(arg0)
1134
- expr_1 = self._expr(arg1)
1135
- if expr_0 is None:
1136
- expr_0 = arg0
1137
- if expr_1 is None:
1138
- expr_1 = arg1
1113
+ def _handle_unop_unpack(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1114
+ pass
1139
1115
 
1140
- try:
1141
- return expr_0 + expr_1
1142
- except TypeError:
1143
- return ailment.Expr.BinaryOp(
1144
- expr.idx,
1145
- "Add",
1146
- [expr_0, expr_1],
1147
- expr.signed,
1148
- floating_point=expr.floating_point,
1149
- rounding_mode=expr.rounding_mode,
1150
- **expr.tags,
1151
- )
1152
-
1153
- def _ail_handle_Sub(self, expr):
1154
- arg0, arg1 = expr.operands
1155
-
1156
- expr_0 = self._expr(arg0) if not isinstance(arg0, claripy.ast.Base) else arg0
1157
- expr_1 = self._expr(arg1) if not isinstance(arg1, claripy.ast.Base) else self._expr(arg1)
1158
-
1159
- if expr_0 is None:
1160
- expr_0 = arg0
1161
- if expr_1 is None:
1162
- expr_1 = arg1
1116
+ def _handle_unop_RSqrtEst(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1117
+ pass
1163
1118
 
1164
- try:
1165
- return expr_0 - expr_1
1166
- except TypeError:
1167
- return ailment.Expr.BinaryOp(
1168
- expr.idx,
1169
- "Sub",
1170
- [expr_0, expr_1],
1171
- expr.signed,
1172
- floating_point=expr.floating_point,
1173
- rounding_mode=expr.rounding_mode,
1174
- **expr.tags,
1175
- )
1176
-
1177
- def _ail_handle_Div(self, expr):
1178
- arg0, arg1 = expr.operands
1179
-
1180
- expr_0 = self._expr(arg0)
1181
- expr_1 = self._expr(arg1)
1182
-
1183
- if expr_0 is None:
1184
- expr_0 = arg0
1185
- if expr_1 is None:
1186
- expr_1 = arg1
1119
+ def _handle_binop_Add(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1120
+ pass
1187
1121
 
1188
- try:
1189
- return expr_0 // expr_1
1190
- except TypeError:
1191
- return ailment.Expr.BinaryOp(
1192
- expr.idx,
1193
- "Div",
1194
- [expr_0, expr_1],
1195
- expr.signed,
1196
- floating_point=expr.floating_point,
1197
- rounding_mode=expr.rounding_mode,
1198
- **expr.tags,
1199
- )
1200
-
1201
- def _ail_handle_DivMod(self, expr):
1202
- arg0, arg1 = expr.operands
1203
-
1204
- expr_0 = self._expr(arg0)
1205
- expr_1 = self._expr(arg1)
1206
-
1207
- if expr_0 is None:
1208
- expr_0 = arg0
1209
- if expr_1 is None:
1210
- expr_1 = arg1
1211
-
1212
- return ailment.Expr.BinaryOp(
1213
- expr.idx,
1214
- "DivMod",
1215
- [expr_0, expr_1],
1216
- expr.signed,
1217
- bits=expr.bits,
1218
- from_bits=expr.from_bits,
1219
- to_bits=expr.to_bits,
1220
- **expr.tags,
1221
- )
1122
+ def _handle_binop_AddF(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1123
+ pass
1222
1124
 
1223
- def _ail_handle_Mod(self, expr):
1224
- arg0, arg1 = expr.operands
1125
+ def _handle_binop_AddV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1126
+ pass
1225
1127
 
1226
- expr_0 = self._expr(arg0)
1227
- expr_1 = self._expr(arg1)
1128
+ def _handle_binop_Sub(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1129
+ pass
1228
1130
 
1229
- if expr_0 is None:
1230
- expr_0 = arg0
1231
- if expr_1 is None:
1232
- expr_1 = arg1
1131
+ def _handle_binop_SubF(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1132
+ pass
1233
1133
 
1234
- try:
1235
- return expr_0 % expr_1
1236
- except TypeError:
1237
- return ailment.Expr.BinaryOp(expr.idx, "Mod", [expr_0, expr_1], expr.signed, **expr.tags)
1134
+ def _handle_binop_SubV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1135
+ pass
1238
1136
 
1239
- def _ail_handle_Mul(self, expr):
1240
- arg0, arg1 = expr.operands
1137
+ def _handle_binop_Mul(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1138
+ pass
1241
1139
 
1242
- expr_0 = self._expr(arg0)
1243
- expr_1 = self._expr(arg1)
1140
+ def _handle_binop_Mull(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1141
+ pass
1244
1142
 
1245
- if expr_0 is None:
1246
- expr_0 = arg0
1247
- if expr_1 is None:
1248
- expr_1 = arg1
1143
+ def _handle_binop_MulF(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1144
+ pass
1249
1145
 
1250
- try:
1251
- return expr_0 * expr_1
1252
- except TypeError:
1253
- return ailment.Expr.BinaryOp(
1254
- expr.idx,
1255
- "Mul",
1256
- [expr_0, expr_1],
1257
- expr.signed,
1258
- bits=expr.bits,
1259
- floating_point=expr.floating_point,
1260
- rounding_mode=expr.rounding_mode,
1261
- **expr.tags,
1262
- )
1263
-
1264
- def _ail_handle_Mull(self, expr):
1265
- arg0, arg1 = expr.operands
1266
-
1267
- expr_0 = self._expr(arg0)
1268
- expr_1 = self._expr(arg1)
1269
-
1270
- if expr_0 is None:
1271
- expr_0 = arg0
1272
- if expr_1 is None:
1273
- expr_1 = arg1
1274
-
1275
- if isinstance(expr_0, claripy.ast.Bits) and isinstance(expr_1, claripy.ast.Bits):
1276
- expr0_ext = claripy.ZeroExt(expr.bits - expr_0.size(), expr_0) if expr.bits > expr_0.size() else expr_0
1277
- expr1_ext = claripy.ZeroExt(expr.bits - expr_1.size(), expr_1) if expr.bits > expr_1.size() else expr_1
1278
- return expr0_ext * expr1_ext
1279
-
1280
- return ailment.Expr.BinaryOp(
1281
- expr.idx,
1282
- "Mull",
1283
- [expr_0, expr_1],
1284
- expr.signed,
1285
- bits=expr.bits,
1286
- floating_point=expr.floating_point,
1287
- rounding_mode=expr.rounding_mode,
1288
- **expr.tags,
1289
- )
1146
+ def _handle_binop_MulV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1147
+ pass
1290
1148
 
1291
- def _ail_handle_And(self, expr):
1292
- arg0, arg1 = expr.operands
1149
+ def _handle_binop_MulHiV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1150
+ pass
1293
1151
 
1294
- expr_0 = self._expr(arg0)
1295
- expr_1 = self._expr(arg1)
1152
+ def _handle_binop_Div(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1153
+ pass
1296
1154
 
1297
- if expr_0 is None:
1298
- expr_0 = arg0
1299
- if expr_1 is None:
1300
- expr_1 = arg1
1155
+ def _handle_binop_DivF(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1156
+ pass
1301
1157
 
1302
- try:
1303
- return expr_0 & expr_1
1304
- except TypeError:
1305
- return ailment.Expr.BinaryOp(expr.idx, "And", [expr_0, expr_1], expr.signed, **expr.tags)
1158
+ def _handle_binop_DivV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1159
+ pass
1306
1160
 
1307
- def _ail_handle_Or(self, expr):
1308
- arg0, arg1 = expr.operands
1161
+ def _handle_binop_Mod(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1162
+ pass
1309
1163
 
1310
- expr_0 = self._expr(arg0)
1311
- expr_1 = self._expr(arg1)
1164
+ def _handle_binop_Xor(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1165
+ pass
1312
1166
 
1313
- if expr_0 is None:
1314
- expr_0 = arg0
1315
- if expr_1 is None:
1316
- expr_1 = arg1
1167
+ def _handle_binop_And(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1168
+ pass
1317
1169
 
1318
- try:
1319
- return expr_0 | expr_1
1320
- except TypeError:
1321
- return ailment.Expr.BinaryOp(expr.idx, "Or", [expr_0, expr_1], expr.signed, **expr.tags)
1170
+ def _handle_binop_LogicalAnd(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1171
+ pass
1322
1172
 
1323
- def _ail_handle_Xor(self, expr):
1324
- arg0, arg1 = expr.operands
1173
+ def _handle_binop_Or(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1174
+ pass
1325
1175
 
1326
- expr_0 = self._expr(arg0)
1327
- expr_1 = self._expr(arg1)
1176
+ def _handle_binop_LogicalOr(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1177
+ pass
1328
1178
 
1329
- if expr_0 is None:
1330
- expr_0 = arg0
1331
- if expr_1 is None:
1332
- expr_1 = arg1
1179
+ def _handle_binop_Shl(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1180
+ pass
1333
1181
 
1334
- try:
1335
- return expr_0 ^ expr_1
1336
- except TypeError:
1337
- return ailment.Expr.BinaryOp(expr.idx, "Xor", [expr_0, expr_1], expr.signed, **expr.tags)
1182
+ def _handle_binop_Shr(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1183
+ pass
1338
1184
 
1339
- def _ail_handle_Shr(self, expr):
1340
- arg0, arg1 = expr.operands
1341
- expr_0 = self._expr(arg0)
1342
- expr_1 = self._expr(arg1)
1185
+ def _handle_binop_Sar(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1186
+ pass
1343
1187
 
1344
- if expr_0 is None:
1345
- expr_0 = arg0
1346
- if expr_1 is None:
1347
- expr_1 = arg1
1188
+ def _handle_binop_CmpF(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1189
+ pass
1348
1190
 
1349
- try:
1350
- if isinstance(expr_1, claripy.ast.BV) and expr_1.concrete:
1351
- return expr_0 >> expr_1.concrete_value
1352
- except TypeError:
1353
- pass
1191
+ def _handle_binop_CmpEQ(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1192
+ pass
1354
1193
 
1355
- return ailment.Expr.BinaryOp(expr.idx, "Shr", [expr_0, expr_1], expr.signed, **expr.tags)
1194
+ def _handle_binop_CmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1195
+ pass
1356
1196
 
1357
- def _ail_handle_Shl(self, expr):
1358
- arg0, arg1 = expr.operands
1359
- expr_0 = self._expr(arg0)
1360
- expr_1 = self._expr(arg1)
1197
+ def _handle_binop_CmpLT(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1198
+ pass
1361
1199
 
1362
- if expr_0 is None:
1363
- expr_0 = arg0
1364
- if expr_1 is None:
1365
- expr_1 = arg1
1200
+ def _handle_binop_CmpLE(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1201
+ pass
1366
1202
 
1367
- if isinstance(expr_0, claripy.ast.BV) and isinstance(expr_1, claripy.ast.BV) and expr_1.concrete:
1368
- return expr_0 << expr_1.concrete_value
1369
- return ailment.Expr.BinaryOp(expr.idx, "Shl", [expr_0, expr_1], expr.signed, **expr.tags)
1203
+ def _handle_binop_CmpGT(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1204
+ pass
1370
1205
 
1371
- def _ail_handle_Sal(self, expr):
1372
- return self._ail_handle_Shl(expr)
1206
+ def _handle_binop_CmpGE(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1207
+ pass
1373
1208
 
1374
- def _ail_handle_Rol(self, expr):
1375
- arg0, arg1 = expr.operands
1376
- expr_0 = self._expr(arg0)
1377
- expr_1 = self._expr(arg1)
1209
+ def _handle_binop_Concat(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1210
+ pass
1378
1211
 
1379
- if expr_0 is None:
1380
- expr_0 = arg0
1381
- if expr_1 is None:
1382
- expr_1 = arg1
1212
+ def _handle_binop_Ror(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1213
+ pass
1383
1214
 
1384
- return ailment.Expr.BinaryOp(expr.idx, "Rol", [expr_0, expr_1], expr.signed, **expr.tags)
1215
+ def _handle_binop_Rol(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1216
+ pass
1385
1217
 
1386
- def _ail_handle_Ror(self, expr):
1387
- arg0, arg1 = expr.operands
1388
- expr_0 = self._expr(arg0)
1389
- expr_1 = self._expr(arg1)
1218
+ def _handle_binop_Carry(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1219
+ pass
1390
1220
 
1391
- if expr_0 is None:
1392
- expr_0 = arg0
1393
- if expr_1 is None:
1394
- expr_1 = arg1
1221
+ def _handle_binop_SCarry(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1222
+ pass
1395
1223
 
1396
- return ailment.Expr.BinaryOp(expr.idx, "Ror", [expr_0, expr_1], expr.signed, **expr.tags)
1224
+ def _handle_binop_SBorrow(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1225
+ pass
1397
1226
 
1398
- def _ail_handle_Sar(self, expr):
1399
- arg0, arg1 = expr.operands
1400
- expr_0 = self._expr(arg0)
1401
- expr_1 = self._expr(arg1)
1227
+ def _handle_binop_InterleaveLOV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1228
+ pass
1402
1229
 
1403
- if expr_0 is None:
1404
- expr_0 = arg0
1405
- if expr_1 is None:
1406
- expr_1 = arg1
1230
+ def _handle_binop_InterleaveHIV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1231
+ pass
1407
1232
 
1408
- if isinstance(expr_0, claripy.ast.Bits) and isinstance(expr_1, claripy.ast.Bits) and expr_1.concrete:
1409
- return expr_0 >> expr_1.concrete_value
1410
- return ailment.Expr.BinaryOp(expr.idx, "Sar", [expr_0, expr_1], expr.signed, **expr.tags)
1233
+ def _handle_binop_CasCmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1234
+ pass
1411
1235
 
1412
- def _ail_handle_Concat(self, expr):
1413
- arg0, arg1 = expr.operands
1414
- expr_0 = self._expr(arg0)
1415
- expr_1 = self._expr(arg1)
1236
+ def _handle_binop_ExpCmpNE(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1237
+ pass
1416
1238
 
1417
- if expr_0 is None:
1418
- expr_0 = arg0
1419
- if expr_1 is None:
1420
- expr_1 = arg1
1239
+ def _handle_binop_SarNV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1240
+ pass
1421
1241
 
1422
- return ailment.Expr.BinaryOp(expr.idx, "Concat", [expr_0, expr_1], expr.signed, **expr.tags)
1242
+ def _handle_binop_ShrNV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1243
+ pass
1423
1244
 
1424
- #
1425
- # Unary operation handlers
1426
- #
1245
+ def _handle_binop_ShlNV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1246
+ pass
1427
1247
 
1428
- def _ail_handle_Convert(self, expr):
1429
- data = self._expr(expr.operand)
1430
- if data is not None and type(data) is int:
1431
- return data
1432
- return None
1248
+ def _handle_binop_CmpEQV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1249
+ pass
1433
1250
 
1434
- def _ail_handle_Not(self, expr):
1435
- data = self._expr(expr.operand)
1436
- if data is None:
1437
- return None
1251
+ def _handle_binop_CmpNEV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1252
+ pass
1438
1253
 
1439
- return ailment.Expr.UnaryOp(expr.idx, "Not", data, **expr.tags)
1254
+ def _handle_binop_CmpGEV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1255
+ pass
1440
1256
 
1441
- def _ail_handle_Neg(self, expr):
1442
- data = self._expr(expr.operand)
1443
- if data is None:
1444
- return None
1257
+ def _handle_binop_CmpGTV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1258
+ pass
1445
1259
 
1446
- return ailment.Expr.UnaryOp(expr.idx, "Neg", data, **expr.tags)
1260
+ def _handle_binop_CmpLEV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1261
+ pass
1447
1262
 
1448
- def _ail_handle_BitwiseNeg(self, expr):
1449
- data = self._expr(expr.operand)
1450
- if data is None:
1451
- return None
1263
+ def _handle_binop_CmpLTV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1264
+ pass
1452
1265
 
1453
- return ailment.Expr.UnaryOp(expr.idx, "BitwiseNeg", data, **expr.tags)
1266
+ def _handle_binop_PermV(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1267
+ pass
1454
1268
 
1269
+ def _handle_binop_Set(self, expr: ailment.expression.BinaryOp) -> DataType_co | None:
1270
+ pass
1455
1271
 
1456
- # Compatibility
1457
- SimEngineLightVEX = SimEngineLightVEXMixin
1458
- SimEngineLightAIL = SimEngineLightAILMixin
1272
+ def _handle_unop_Clz(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1273
+ pass
1274
+
1275
+ def _handle_unop_Ctz(self, expr: ailment.expression.UnaryOp) -> DataType_co | None:
1276
+ pass