angr 9.2.118__py3-none-manylinux2014_aarch64.whl → 9.2.119__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 (76) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +43 -1
  3. angr/analyses/cfg/cfg_fast.py +135 -23
  4. angr/analyses/decompiler/ail_simplifier.py +1 -1
  5. angr/analyses/decompiler/clinic.py +23 -12
  6. angr/analyses/decompiler/condition_processor.py +41 -16
  7. angr/analyses/decompiler/decompiler.py +3 -0
  8. angr/analyses/decompiler/jumptable_entry_condition_rewriter.py +1 -1
  9. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +7 -4
  10. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +6 -2
  11. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +19 -19
  12. angr/analyses/decompiler/structured_codegen/c.py +9 -2
  13. angr/analyses/decompiler/structuring/dream.py +8 -7
  14. angr/analyses/decompiler/structuring/phoenix.py +3 -3
  15. angr/analyses/propagator/engine_ail.py +2 -1
  16. angr/analyses/reaching_definitions/function_handler.py +6 -2
  17. angr/analyses/stack_pointer_tracker.py +29 -11
  18. angr/analyses/typehoon/translator.py +19 -2
  19. angr/analyses/typehoon/typeconsts.py +8 -0
  20. angr/analyses/variable_recovery/engine_vex.py +7 -10
  21. angr/calling_conventions.py +69 -24
  22. angr/concretization_strategies/norepeats.py +3 -3
  23. angr/engines/concrete.py +1 -1
  24. angr/engines/light/engine.py +6 -11
  25. angr/engines/pcode/engine.py +2 -2
  26. angr/engines/soot/engine.py +5 -5
  27. angr/engines/soot/expressions/condition.py +1 -1
  28. angr/engines/soot/statements/goto.py +1 -1
  29. angr/engines/soot/statements/if_.py +1 -1
  30. angr/engines/soot/statements/throw.py +1 -1
  31. angr/engines/successors.py +1 -1
  32. angr/engines/unicorn.py +2 -2
  33. angr/engines/vex/heavy/heavy.py +2 -2
  34. angr/errors.py +4 -0
  35. angr/exploration_techniques/driller_core.py +2 -3
  36. angr/exploration_techniques/suggestions.py +2 -2
  37. angr/knowledge_plugins/cfg/cfg_model.py +2 -1
  38. angr/knowledge_plugins/cfg/memory_data.py +1 -0
  39. angr/misc/telemetry.py +54 -0
  40. angr/procedures/java/unconstrained.py +1 -1
  41. angr/procedures/java_jni/__init__.py +21 -13
  42. angr/procedures/java_jni/string_operations.py +1 -1
  43. angr/procedures/java_lang/double.py +1 -1
  44. angr/procedures/java_lang/string.py +1 -1
  45. angr/procedures/java_util/scanner_nextline.py +1 -1
  46. angr/procedures/linux_kernel/vsyscall.py +1 -1
  47. angr/procedures/stubs/Redirect.py +1 -1
  48. angr/procedures/stubs/UserHook.py +1 -1
  49. angr/procedures/stubs/format_parser.py +1 -1
  50. angr/sim_procedure.py +5 -5
  51. angr/sim_state.py +21 -34
  52. angr/sim_type.py +42 -0
  53. angr/simos/javavm.py +7 -12
  54. angr/simos/linux.py +1 -1
  55. angr/simos/simos.py +1 -1
  56. angr/simos/windows.py +1 -1
  57. angr/state_hierarchy.py +1 -1
  58. angr/state_plugins/preconstrainer.py +2 -2
  59. angr/state_plugins/scratch.py +1 -1
  60. angr/state_plugins/solver.py +1 -1
  61. angr/state_plugins/trace_additions.py +8 -8
  62. angr/storage/file.py +12 -12
  63. angr/storage/memory_mixins/actions_mixin.py +1 -1
  64. angr/storage/memory_mixins/convenient_mappings_mixin.py +6 -8
  65. angr/storage/memory_mixins/multi_value_merger_mixin.py +5 -5
  66. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +1 -1
  67. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  68. angr/storage/memory_mixins/smart_find_mixin.py +2 -2
  69. angr/storage/memory_object.py +7 -9
  70. angr/utils/timing.py +30 -18
  71. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/METADATA +8 -6
  72. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/RECORD +76 -75
  73. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/LICENSE +0 -0
  74. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/WHEEL +0 -0
  75. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/entry_points.txt +0 -0
  76. {angr-9.2.118.dist-info → angr-9.2.119.dist-info}/top_level.txt +0 -0
@@ -60,12 +60,12 @@ class InlinedStringTransformationState:
60
60
  def _get_weakref(self):
61
61
  return self
62
62
 
63
- def reg_store(self, reg: Register, value: claripy.Bits) -> None:
63
+ def reg_store(self, reg: Register, value: claripy.ast.Bits) -> None:
64
64
  self.registers.store(
65
65
  reg.reg_offset, value, size=value.size() // self.arch.byte_width, endness=str(self.arch.register_endness)
66
66
  )
67
67
 
68
- def reg_load(self, reg: Register) -> claripy.Bits | None:
68
+ def reg_load(self, reg: Register) -> claripy.ast.Bits | None:
69
69
  try:
70
70
  return self.registers.load(
71
71
  reg.reg_offset, size=reg.size, endness=self.arch.register_endness, fill_missing=False
@@ -73,19 +73,19 @@ class InlinedStringTransformationState:
73
73
  except SimMemoryMissingError:
74
74
  return None
75
75
 
76
- def mem_store(self, addr: int, value: claripy.Bits, endness: str) -> None:
76
+ def mem_store(self, addr: int, value: claripy.ast.Bits, endness: str) -> None:
77
77
  self.memory.store(addr, value, size=value.size() // self.arch.byte_width, endness=endness)
78
78
 
79
- def mem_load(self, addr: int, size: int, endness) -> claripy.Bits | None:
79
+ def mem_load(self, addr: int, size: int, endness) -> claripy.ast.Bits | None:
80
80
  try:
81
81
  return self.memory.load(addr, size=size, endness=str(endness), fill_missing=False)
82
82
  except SimMemoryMissingError:
83
83
  return None
84
84
 
85
- def vvar_store(self, vvar: VirtualVariable, value: claripy.Bits | None) -> None:
85
+ def vvar_store(self, vvar: VirtualVariable, value: claripy.ast.Bits | None) -> None:
86
86
  self.virtual_variables[vvar.varid] = value
87
87
 
88
- def vvar_load(self, vvar: VirtualVariable) -> claripy.Bits | None:
88
+ def vvar_load(self, vvar: VirtualVariable) -> claripy.ast.Bits | None:
89
89
  if vvar.varid in self.virtual_variables:
90
90
  return self.virtual_variables[vvar.varid]
91
91
  return None
@@ -109,7 +109,7 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
109
109
  self.MASK = 0xFFFF_FFFF if self.arch.bits == 32 else 0xFFFF_FFFF_FFFF_FFFF
110
110
 
111
111
  state = InlinedStringTransformationState(project)
112
- self.stack_accesses: defaultdict[int, list[tuple[str, CodeLocation, claripy.Bits]]] = defaultdict(list)
112
+ self.stack_accesses: defaultdict[int, list[tuple[str, CodeLocation, claripy.ast.Bits]]] = defaultdict(list)
113
113
  self.finished: bool = False
114
114
 
115
115
  i = 0
@@ -140,7 +140,7 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
140
140
  if v0_and_type is not None:
141
141
  v0 = v0_and_type[0]
142
142
  v1 = self._expr(addr.operands[1])
143
- if isinstance(v1, claripy.Bits) and v1.concrete:
143
+ if isinstance(v1, claripy.ast.Bits) and v1.concrete:
144
144
  return (v0 + v1.concrete_value) & self.MASK, "stack"
145
145
  return None
146
146
 
@@ -148,7 +148,7 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
148
148
  if isinstance(stmt.dst, VirtualVariable):
149
149
  if stmt.dst.was_reg:
150
150
  val = self._expr(stmt.src)
151
- if isinstance(val, claripy.Bits):
151
+ if isinstance(val, claripy.ast.Bits):
152
152
  self.state.vvar_store(stmt.dst, val)
153
153
  elif stmt.dst.was_stack:
154
154
  addr = (stmt.dst.stack_offset + self.STACK_BASE) & self.MASK
@@ -190,9 +190,9 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
190
190
  if isinstance(stmt.true_target, Const) and isinstance(stmt.false_target, Const):
191
191
  cond = self._expr(stmt.condition)
192
192
  if cond is not None:
193
- if isinstance(cond, claripy.Bits) and cond.concrete_value == 1:
193
+ if isinstance(cond, claripy.ast.Bits) and cond.concrete_value == 1:
194
194
  self.pc = stmt.true_target.value
195
- elif isinstance(cond, claripy.Bits) and cond.concrete_value == 0:
195
+ elif isinstance(cond, claripy.ast.Bits) and cond.concrete_value == 0:
196
196
  self.pc = stmt.false_target.value
197
197
 
198
198
  def _handle_Const(self, expr):
@@ -220,7 +220,7 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
220
220
  if expr.was_stack:
221
221
  addr = (expr.stack_offset + self.STACK_BASE) & self.MASK
222
222
  v = self.state.mem_load(addr, expr.size, self.arch.memory_endness)
223
- if isinstance(v, claripy.Bits):
223
+ if isinstance(v, claripy.ast.Bits):
224
224
  # log it
225
225
  for i in range(expr.size):
226
226
  byte_off = i
@@ -240,7 +240,7 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
240
240
 
241
241
  def _handle_Convert(self, expr: Convert):
242
242
  v = self._expr(expr.operand)
243
- if isinstance(v, claripy.Bits):
243
+ if isinstance(v, claripy.ast.Bits):
244
244
  if expr.to_bits > expr.from_bits:
245
245
  if not expr.is_signed:
246
246
  return claripy.ZeroExt(expr.to_bits - expr.from_bits, v)
@@ -252,37 +252,37 @@ class InlinedStringTransformationAILEngine(SimEngineLightAILMixin):
252
252
 
253
253
  def _handle_CmpEQ(self, expr):
254
254
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
255
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
255
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
256
256
  return claripy.BVV(1, 1) if op0.concrete_value == op1.concrete_value else claripy.BVV(0, 1)
257
257
  return None
258
258
 
259
259
  def _handle_CmpNE(self, expr):
260
260
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
261
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
261
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
262
262
  return claripy.BVV(1, 1) if op0.concrete_value != op1.concrete_value else claripy.BVV(0, 1)
263
263
  return None
264
264
 
265
265
  def _handle_CmpLT(self, expr):
266
266
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
267
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
267
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
268
268
  return claripy.BVV(1, 1) if op0.concrete_value < op1.concrete_value else claripy.BVV(0, 1)
269
269
  return None
270
270
 
271
271
  def _handle_CmpLE(self, expr):
272
272
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
273
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
273
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
274
274
  return claripy.BVV(1, 1) if op0.concrete_value <= op1.concrete_value else claripy.BVV(0, 1)
275
275
  return None
276
276
 
277
277
  def _handle_CmpGT(self, expr):
278
278
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
279
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
279
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
280
280
  return claripy.BVV(1, 1) if op0.concrete_value > op1.concrete_value else claripy.BVV(0, 1)
281
281
  return None
282
282
 
283
283
  def _handle_CmpGE(self, expr):
284
284
  op0, op1 = self._expr(expr.operands[0]), self._expr(expr.operands[1])
285
- if isinstance(op0, claripy.Bits) and isinstance(op1, claripy.Bits) and op0.concrete and op1.concrete:
285
+ if isinstance(op0, claripy.ast.Bits) and isinstance(op1, claripy.ast.Bits) and op0.concrete and op1.concrete:
286
286
  return claripy.BVV(1, 1) if op0.concrete_value >= op1.concrete_value else claripy.BVV(0, 1)
287
287
  return None
288
288
 
@@ -31,6 +31,8 @@ from ....sim_type import (
31
31
  SimTypeLength,
32
32
  SimTypeReg,
33
33
  dereference_simtype,
34
+ SimTypeInt128,
35
+ SimTypeInt256,
34
36
  )
35
37
  from ....knowledge_plugins.functions import Function
36
38
  from ....sim_variable import SimVariable, SimTemporaryVariable, SimStackVariable, SimMemoryVariable
@@ -3479,8 +3481,13 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3479
3481
 
3480
3482
  def _handle_Expr_Convert(self, expr: Expr.Convert, **kwargs):
3481
3483
  # width of converted type is easy
3482
- if 64 >= expr.to_bits > 32:
3483
- dst_type: SimTypeInt | SimTypeChar = SimTypeLongLong()
3484
+ dst_type: SimTypeInt | SimTypeChar
3485
+ if 258 >= expr.to_bits > 128:
3486
+ dst_type = SimTypeInt256()
3487
+ elif 128 >= expr.to_bits > 64:
3488
+ dst_type = SimTypeInt128()
3489
+ elif 64 >= expr.to_bits > 32:
3490
+ dst_type = SimTypeLongLong()
3484
3491
  elif 32 >= expr.to_bits > 16:
3485
3492
  dst_type = SimTypeInt()
3486
3493
  elif 16 >= expr.to_bits > 8:
@@ -767,7 +767,7 @@ class DreamStructurer(StructurerBase):
767
767
  if (
768
768
  arg.op == "__eq__"
769
769
  and arg.args[0] is jumptable_var
770
- and isinstance(arg.args[1], claripy.Bits)
770
+ and isinstance(arg.args[1], claripy.ast.Bits)
771
771
  and arg.args[1].concrete
772
772
  ):
773
773
  # found it
@@ -780,7 +780,7 @@ class DreamStructurer(StructurerBase):
780
780
  # unsupported
781
781
  return None
782
782
  elif cond.op == "__eq__":
783
- if cond.args[0] is jumptable_var and isinstance(cond.args[1], claripy.Bits) and cond.args[1].concrete:
783
+ if cond.args[0] is jumptable_var and isinstance(cond.args[1], claripy.ast.Bits) and cond.args[1].concrete:
784
784
  # found it
785
785
  eq_condition = cond
786
786
  true_node = cond_node.true_node
@@ -800,7 +800,8 @@ class DreamStructurer(StructurerBase):
800
800
  return None
801
801
 
802
802
  return CodeNode(
803
- ConditionNode(cond_node.addr, claripy.true, remaining_cond, true_node, false_node=false_node), eq_condition
803
+ ConditionNode(cond_node.addr, claripy.true(), remaining_cond, true_node, false_node=false_node),
804
+ eq_condition,
804
805
  )
805
806
 
806
807
  def _switch_check_existence_of_jumptable_entries(
@@ -942,11 +943,11 @@ class DreamStructurer(StructurerBase):
942
943
  )
943
944
  ],
944
945
  )
945
- case_node = SequenceNode(0, nodes=[CodeNode(case_inner_node, claripy.true)])
946
+ case_node = SequenceNode(0, nodes=[CodeNode(case_inner_node, claripy.true())])
946
947
  converted_nodes[entry_addr] = case_node
947
948
  continue
948
949
 
949
- case_node = SequenceNode(entry_node.addr, nodes=[CodeNode(entry_node.node, claripy.true)])
950
+ case_node = SequenceNode(entry_node.addr, nodes=[CodeNode(entry_node.node, claripy.true())])
950
951
  to_remove.add(entry_node)
951
952
  entry_node_idx = seq.nodes.index(entry_node)
952
953
 
@@ -966,7 +967,7 @@ class DreamStructurer(StructurerBase):
966
967
  )
967
968
  ],
968
969
  )
969
- case_node = SequenceNode(0, nodes=[CodeNode(case_inner_node, claripy.true)])
970
+ case_node = SequenceNode(0, nodes=[CodeNode(case_inner_node, claripy.true())])
970
971
  converted_nodes[entry_addr] = case_node
971
972
  continue
972
973
 
@@ -1097,7 +1098,7 @@ class DreamStructurer(StructurerBase):
1097
1098
  def _nodes_guarded_by_common_subexpr(seq, common_subexpr, starting_idx):
1098
1099
  candidates = []
1099
1100
 
1100
- if common_subexpr is claripy.true:
1101
+ if common_subexpr is claripy.true():
1101
1102
  return []
1102
1103
  for j, node_1 in enumerate(seq.nodes[starting_idx:]):
1103
1104
  rcond_1 = getattr(node_1, "reaching_condition", None)
@@ -368,7 +368,7 @@ class PhoenixStructurer(StructurerBase):
368
368
  jump_node = Block(last_stmt.ins_addr, None, statements=[cond_jump])
369
369
  cond_jump_node = ConditionNode(last_stmt.ins_addr, None, edge_cond_right, jump_node)
370
370
  new_node = SequenceNode(node.addr, nodes=[node, cond_jump_node, left])
371
- loop_node = LoopNode("while", claripy.true, new_node, addr=node.addr)
371
+ loop_node = LoopNode("while", claripy.true(), new_node, addr=node.addr)
372
372
 
373
373
  # on the original graph
374
374
  self.replace_nodes(graph, node, loop_node, old_node_1=left, self_loop=False)
@@ -392,7 +392,7 @@ class PhoenixStructurer(StructurerBase):
392
392
  self._remove_last_statement_if_jump(head_block)
393
393
  cond_break = ConditionalBreakNode(node.addr, edge_cond_right, right.addr)
394
394
  new_node = SequenceNode(node.addr, nodes=[node, cond_break, left])
395
- loop_node = LoopNode("while", claripy.true, new_node, addr=node.addr)
395
+ loop_node = LoopNode("while", claripy.true(), new_node, addr=node.addr)
396
396
 
397
397
  # on the original graph
398
398
  self.replace_nodes(graph, node, loop_node, old_node_1=left, self_loop=False)
@@ -572,7 +572,7 @@ class PhoenixStructurer(StructurerBase):
572
572
  seen_nodes.add(next_node)
573
573
  seq_node.nodes.append(next_node)
574
574
 
575
- loop_node = LoopNode("while", claripy.true, seq_node, addr=node.addr)
575
+ loop_node = LoopNode("while", claripy.true(), seq_node, addr=node.addr)
576
576
 
577
577
  # on the original graph
578
578
  for node_ in seq_node.nodes:
@@ -141,13 +141,14 @@ class SimEnginePropagatorAIL(
141
141
  size = data_v.size() // self.arch.byte_width
142
142
  to_store = PropValue.from_value_and_details(data_v, size, expr, self._codeloc())
143
143
  else:
144
+ expr = data.one_expr
144
145
  size = stmt.size
145
146
  to_store = data.with_details(
146
147
  stmt.size, data.one_expr if data.one_expr is not None else stmt.data, self._codeloc()
147
148
  )
148
149
 
149
150
  # ensure there isn't a Tmp variable in the data
150
- if not self.has_tmpexpr(expr):
151
+ if expr is None or not self.has_tmpexpr(expr):
151
152
  # Storing data to a stack variable
152
153
  self.state.store_stack_variable(sp_offset, to_store, endness=stmt.endness)
153
154
 
@@ -370,10 +370,14 @@ class FunctionHandler:
370
370
  data.prototype = state.analysis.project.factory.function_prototype()
371
371
  data.guessed_prototype = True
372
372
 
373
- if data.prototype is not None and data.function is not None:
373
+ if data.prototype is not None:
374
374
  # make sure the function prototype is resolved.
375
375
  # TODO: Cache resolved function prototypes globally
376
- prototype_libname = data.function.prototype_libname or hook_libname
376
+ prototype_libname = (
377
+ data.function.prototype_libname
378
+ if data.function is not None and data.function.prototype_libname
379
+ else hook_libname
380
+ )
377
381
  type_collections = []
378
382
  if prototype_libname is not None:
379
383
  prototype_lib = SIM_LIBRARIES[prototype_libname]
@@ -1,7 +1,7 @@
1
1
  # pylint:disable=abstract-method,ungrouped-imports
2
2
  from __future__ import annotations
3
3
 
4
- from typing import TYPE_CHECKING
4
+ from typing import Any, TYPE_CHECKING
5
5
  import re
6
6
  import logging
7
7
  from collections import defaultdict
@@ -179,7 +179,13 @@ class FrozenStackPointerTrackerState:
179
179
 
180
180
  __slots__ = "regs", "memory", "is_tracking_memory", "resilient"
181
181
 
182
- def __init__(self, regs, memory, is_tracking_memory, resilient):
182
+ def __init__(
183
+ self,
184
+ regs,
185
+ memory,
186
+ is_tracking_memory,
187
+ resilient,
188
+ ):
183
189
  self.regs = regs
184
190
  self.memory = memory
185
191
  self.is_tracking_memory = is_tracking_memory
@@ -193,8 +199,10 @@ class FrozenStackPointerTrackerState:
193
199
  return hash((FrozenStackPointerTrackerState, self.regs, self.memory, self.is_tracking_memory))
194
200
  return hash((FrozenStackPointerTrackerState, self.regs, self.is_tracking_memory))
195
201
 
196
- def merge(self, other):
197
- return self.unfreeze().merge(other.unfreeze()).freeze()
202
+ def merge(
203
+ self, other, addr: int, reg_merge_cache: dict[tuple[int, int], Any], mem_merge_cache: dict[tuple[int, int], Any]
204
+ ):
205
+ return self.unfreeze().merge(other.unfreeze(), addr, reg_merge_cache, mem_merge_cache).freeze()
198
206
 
199
207
  def __eq__(self, other):
200
208
  if type(other) is FrozenStackPointerTrackerState or isinstance(other, FrozenStackPointerTrackerState):
@@ -278,16 +286,18 @@ class StackPointerTrackerState:
278
286
  return hash((StackPointerTrackerState, self.regs, self.memory, self.is_tracking_memory))
279
287
  return hash((StackPointerTrackerState, self.regs, self.is_tracking_memory))
280
288
 
281
- def merge(self, other):
289
+ def merge(
290
+ self, other, addr: int, reg_merge_cache: dict[tuple[int, int], Any], mem_merge_cache: dict[tuple[int, int], Any]
291
+ ):
282
292
  return StackPointerTrackerState(
283
- regs=_dict_merge(self.regs, other.regs, self.resilient),
284
- memory=_dict_merge(self.memory, other.memory, self.resilient),
293
+ regs=_dict_merge(self.regs, other.regs, self.resilient, addr, reg_merge_cache),
294
+ memory=_dict_merge(self.memory, other.memory, self.resilient, addr, mem_merge_cache),
285
295
  is_tracking_memory=self.is_tracking_memory and other.is_tracking_memory,
286
296
  resilient=self.resilient or other.resilient,
287
297
  )
288
298
 
289
299
 
290
- def _dict_merge(d1, d2, resilient: bool):
300
+ def _dict_merge(d1, d2, resilient: bool, addr: int, merge_cache: dict[tuple[int, int], Any]):
291
301
  all_keys = set(d1.keys()) | set(d2.keys())
292
302
  merged = {}
293
303
  for k in all_keys:
@@ -299,7 +309,12 @@ def _dict_merge(d1, d2, resilient: bool):
299
309
  merged[k] = d1[k]
300
310
  else: # d1[k] != d2[k]
301
311
  if resilient and isinstance(d1[k], OffsetVal) and isinstance(d2[k], OffsetVal):
302
- merged[k] = min(d1[k], d2[k])
312
+ if (addr, k) in merge_cache:
313
+ merged[k] = merge_cache[(addr, k)]
314
+ else:
315
+ v = min(d1[k], d2[k])
316
+ merge_cache[(addr, k)] = v
317
+ merged[k] = v
303
318
  else:
304
319
  merged[k] = TOP
305
320
  return merged
@@ -350,6 +365,9 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
350
365
  self._reg_value_at_block_start = defaultdict(dict)
351
366
  self.cross_insn_opt = cross_insn_opt
352
367
  self._resilient = resilient
368
+ # in resilience mode, cache previously merged values to ensure we reach a fixed point
369
+ self._reg_merge_cache = {}
370
+ self._mem_merge_cache = {}
353
371
 
354
372
  if initial_reg_values:
355
373
  self._reg_value_at_block_start[func.addr if func is not None else block.addr] = initial_reg_values
@@ -492,7 +510,7 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
492
510
  def _set_state(self, addr, new_val, pre_or_post):
493
511
  previous_val = self._state_for(addr, pre_or_post)
494
512
  if previous_val is not None:
495
- new_val = previous_val.merge(new_val)
513
+ new_val = previous_val.merge(new_val, addr, self._reg_merge_cache, self._mem_merge_cache)
496
514
  if addr not in self.states:
497
515
  self.states[addr] = {}
498
516
  self.states[addr][pre_or_post] = new_val
@@ -808,7 +826,7 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
808
826
  def _merge_states(self, node, *states: StackPointerTrackerState):
809
827
  merged_state = states[0]
810
828
  for other in states[1:]:
811
- merged_state = merged_state.merge(other)
829
+ merged_state = merged_state.merge(other, node.addr, self._reg_merge_cache, self._mem_merge_cache)
812
830
  return merged_state, merged_state == states[0]
813
831
 
814
832
  def _find_callees(self, node) -> list[Function]:
@@ -1,3 +1,4 @@
1
+ # pylint:disable=unused-argument,no-self-use
1
2
  from __future__ import annotations
2
3
  from itertools import count
3
4
 
@@ -8,11 +9,15 @@ from .typeconsts import TypeConstant
8
9
 
9
10
 
10
11
  class SimTypeTempRef(sim_type.SimType):
12
+ """
13
+ Represents a temporary reference to another type. TypeVariableReference is translated to SimTypeTempRef.
14
+ """
15
+
11
16
  def __init__(self, typevar):
12
17
  super().__init__()
13
18
  self.typevar = typevar
14
19
 
15
- def c_repr(self):
20
+ def c_repr(self, **kwargs):
16
21
  return "<SimTypeTempRef>"
17
22
 
18
23
 
@@ -141,7 +146,10 @@ class TypeTranslator:
141
146
  return sim_type.SimTypeLongLong(signed=False).with_arch(self.arch)
142
147
 
143
148
  def _translate_Int128(self, tc): # pylint:disable=unused-argument
144
- return sim_type.SimTypeNum(128, signed=False).with_arch(self.arch)
149
+ return sim_type.SimTypeInt128(signed=False).with_arch(self.arch)
150
+
151
+ def _translate_Int256(self, tc): # pylint:disable=unused-argument
152
+ return sim_type.SimTypeInt256(signed=False).with_arch(self.arch)
145
153
 
146
154
  def _translate_TypeVariableReference(self, tc):
147
155
  if tc.typevar in self.translated:
@@ -176,6 +184,12 @@ class TypeTranslator:
176
184
  # SimType handlers
177
185
  #
178
186
 
187
+ def _translate_SimTypeInt128(self, st: sim_type.SimTypeChar) -> typeconsts.Int128:
188
+ return typeconsts.Int128()
189
+
190
+ def _translate_SimTypeInt256(self, st: sim_type.SimTypeChar) -> typeconsts.Int256:
191
+ return typeconsts.Int256()
192
+
179
193
  def _translate_SimTypeInt(self, st: sim_type.SimTypeInt) -> typeconsts.Int32:
180
194
  return typeconsts.Int32()
181
195
 
@@ -220,6 +234,7 @@ TypeConstHandlers = {
220
234
  typeconsts.Int32: TypeTranslator._translate_Int32,
221
235
  typeconsts.Int64: TypeTranslator._translate_Int64,
222
236
  typeconsts.Int128: TypeTranslator._translate_Int128,
237
+ typeconsts.Int256: TypeTranslator._translate_Int256,
223
238
  typeconsts.TypeVariableReference: TypeTranslator._translate_TypeVariableReference,
224
239
  }
225
240
 
@@ -230,6 +245,8 @@ SimTypeHandlers = {
230
245
  sim_type.SimTypeLong: TypeTranslator._translate_SimTypeLong,
231
246
  sim_type.SimTypeLongLong: TypeTranslator._translate_SimTypeLongLong,
232
247
  sim_type.SimTypeChar: TypeTranslator._translate_SimTypeChar,
248
+ sim_type.SimTypeInt128: TypeTranslator._translate_SimTypeInt128,
249
+ sim_type.SimTypeInt256: TypeTranslator._translate_SimTypeInt256,
233
250
  sim_type.SimStruct: TypeTranslator._translate_SimStruct,
234
251
  sim_type.SimTypeArray: TypeTranslator._translate_SimTypeArray,
235
252
  }
@@ -100,6 +100,13 @@ class Int128(Int):
100
100
  return "int128"
101
101
 
102
102
 
103
+ class Int256(Int):
104
+ SIZE = 32
105
+
106
+ def __repr__(self, memo=None):
107
+ return "int256"
108
+
109
+
103
110
  class FloatBase(TypeConstant):
104
111
  def __repr__(self, memo=None):
105
112
  return "floatbase"
@@ -282,6 +289,7 @@ def int_type(bits: int) -> Int | None:
282
289
  32: Int32,
283
290
  64: Int64,
284
291
  128: Int128,
292
+ 256: Int256,
285
293
  }
286
294
  if bits in mapping:
287
295
  return mapping[bits]()
@@ -254,10 +254,13 @@ class SimEngineVRVEX(
254
254
  typevar = typevars.DerivedTypeVariable(r0.typevar, typevars.AddN(r1.data.concrete_value))
255
255
 
256
256
  sum_ = r0.data + r1.data
257
+ tc = set()
258
+ if r0.typevar is not None and r1.typevar is not None:
259
+ tc.add(typevars.Subtype(r0.typevar, r1.typevar))
257
260
  return RichR(
258
261
  sum_,
259
262
  typevar=typevar,
260
- type_constraints={typevars.Subtype(r0.typevar, r1.typevar)},
263
+ type_constraints=tc,
261
264
  )
262
265
 
263
266
  def _handle_Sub(self, expr):
@@ -501,6 +504,9 @@ class SimEngineVRVEX(
501
504
  def _handle_Clz(self, expr):
502
505
  return RichR(self.state.top(expr.result_size(self.tyenv)))
503
506
 
507
+ def _handle_Ctz(self, expr):
508
+ return RichR(self.state.top(expr.result_size(self.tyenv)))
509
+
504
510
  def _handle_Mull(self, expr):
505
511
  return RichR(self.state.top(expr.result_size(self.tyenv)))
506
512
 
@@ -553,15 +559,6 @@ class SimEngineVRVEX(
553
559
  _, _ = self._expr(expr.args[0]), self._expr(expr.args[1])
554
560
  return RichR(self.state.top(expr.result_size(self.tyenv)))
555
561
 
556
- def _handle_Clz(self, expr):
557
- arg0 = expr.args[0]
558
- expr_0 = self._expr(arg0)
559
- if expr_0 is None:
560
- return None
561
- if self.state.is_top(expr_0.data):
562
- return RichR(self.state.top(expr_0.data.size()))
563
- return RichR(self.state.top(expr_0.data.size()))
564
-
565
562
  _handle_CmpEQ_v = _handle_Cmp_v
566
563
  _handle_CmpNE_v = _handle_Cmp_v
567
564
  _handle_CmpLE_v = _handle_Cmp_v