angr 9.2.64__py3-none-manylinux2014_x86_64.whl → 9.2.66__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (44) hide show
  1. angr/__init__.py +55 -2
  2. angr/analyses/calling_convention.py +4 -3
  3. angr/analyses/cfg/cfg_base.py +2 -2
  4. angr/analyses/cfg/cfg_fast.py +128 -60
  5. angr/analyses/decompiler/ail_simplifier.py +1 -2
  6. angr/analyses/decompiler/block_simplifier.py +4 -3
  7. angr/analyses/decompiler/callsite_maker.py +1 -1
  8. angr/analyses/decompiler/condition_processor.py +5 -3
  9. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +51 -8
  10. angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
  11. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +92 -0
  12. angr/analyses/decompiler/structured_codegen/c.py +59 -6
  13. angr/analyses/decompiler/utils.py +1 -1
  14. angr/analyses/find_objects_static.py +4 -4
  15. angr/analyses/propagator/engine_ail.py +2 -1
  16. angr/analyses/reaching_definitions/__init__.py +1 -3
  17. angr/analyses/reaching_definitions/dep_graph.py +33 -4
  18. angr/analyses/reaching_definitions/engine_ail.py +5 -6
  19. angr/analyses/reaching_definitions/engine_vex.py +6 -7
  20. angr/analyses/reaching_definitions/external_codeloc.py +0 -27
  21. angr/analyses/reaching_definitions/function_handler.py +145 -23
  22. angr/analyses/reaching_definitions/rd_initializer.py +221 -0
  23. angr/analyses/reaching_definitions/rd_state.py +95 -153
  24. angr/analyses/reaching_definitions/reaching_definitions.py +15 -3
  25. angr/calling_conventions.py +2 -2
  26. angr/code_location.py +24 -0
  27. angr/exploration_techniques/__init__.py +28 -0
  28. angr/knowledge_plugins/cfg/cfg_model.py +1 -1
  29. angr/knowledge_plugins/key_definitions/__init__.py +12 -1
  30. angr/knowledge_plugins/key_definitions/atoms.py +9 -0
  31. angr/knowledge_plugins/key_definitions/definition.py +13 -18
  32. angr/knowledge_plugins/key_definitions/live_definitions.py +350 -106
  33. angr/project.py +1 -1
  34. angr/sim_manager.py +15 -0
  35. angr/sim_state.py +3 -3
  36. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +56 -8
  37. angr/storage/memory_object.py +3 -1
  38. angr/utils/typing.py +16 -0
  39. {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/METADATA +8 -8
  40. {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/RECORD +43 -41
  41. {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/WHEEL +1 -1
  42. angr/analyses/decompiler/peephole_optimizations/conv_const_mull_a_shift.py +0 -75
  43. {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/LICENSE +0 -0
  44. {angr-9.2.64.dist-info → angr-9.2.66.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
+ from typing import Optional, Iterable, Dict, Set, Generator, Tuple, Union, Any, TYPE_CHECKING, overload, Type
1
2
  import weakref
2
- from typing import Optional, Iterable, Dict, Set, Generator, Tuple, Union, Any, TYPE_CHECKING
3
3
  import logging
4
+ from enum import Enum, auto
4
5
 
5
6
  from collections import defaultdict
6
7
 
@@ -8,23 +9,36 @@ import claripy
8
9
  from claripy.annotation import Annotation
9
10
  import archinfo
10
11
 
11
- from ...errors import SimMemoryMissingError, SimMemoryError
12
- from ...storage.memory_mixins import MultiValuedMemory
13
- from ...storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
14
- from ...engines.light import SpOffset
15
- from ...code_location import CodeLocation
12
+ from angr.misc.ux import deprecated
13
+ from angr.errors import SimMemoryMissingError, SimMemoryError
14
+ from angr.storage.memory_mixins import MultiValuedMemory
15
+ from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
16
+ from angr.engines.light import SpOffset
17
+ from angr.code_location import CodeLocation, ExternalCodeLocation
16
18
  from .atoms import Atom, Register, MemoryLocation, Tmp, ConstantSrc
17
19
  from .definition import Definition, Tag
18
20
  from .heap_address import HeapAddress
19
21
  from .uses import Uses
20
22
 
21
23
  if TYPE_CHECKING:
24
+ from angr.project import Project
22
25
  from angr.storage import SimMemoryObject
23
26
 
24
27
 
25
28
  l = logging.getLogger(name=__name__)
26
29
 
27
30
 
31
+ class DerefSize(Enum):
32
+ """
33
+ An enum for specialized kinds of dereferences
34
+
35
+ NULL_TERMINATE - Dereference until the first byte which could be a literal null. Return a value including the
36
+ terminator.
37
+ """
38
+
39
+ NULL_TERMINATE = auto()
40
+
41
+
28
42
  #
29
43
  # Annotations
30
44
  #
@@ -81,11 +95,13 @@ class LiveDefinitions:
81
95
  "project",
82
96
  "arch",
83
97
  "track_tmps",
84
- "register_definitions",
85
- "stack_definitions",
86
- "heap_definitions",
87
- "memory_definitions",
98
+ "registers",
99
+ "stack",
100
+ "heap",
101
+ "memory",
88
102
  "tmps",
103
+ "others",
104
+ "other_uses",
89
105
  "register_uses",
90
106
  "stack_uses",
91
107
  "heap_uses",
@@ -101,23 +117,25 @@ class LiveDefinitions:
101
117
  arch: archinfo.Arch,
102
118
  track_tmps: bool = False,
103
119
  canonical_size=8,
104
- register_definitions=None,
105
- stack_definitions=None,
106
- memory_definitions=None,
107
- heap_definitions=None,
120
+ registers=None,
121
+ stack=None,
122
+ memory=None,
123
+ heap=None,
108
124
  tmps=None,
125
+ others=None,
109
126
  register_uses=None,
110
127
  stack_uses=None,
111
128
  heap_uses=None,
112
129
  memory_uses=None,
113
130
  tmp_uses=None,
131
+ other_uses=None,
114
132
  ):
115
- self.project = None
133
+ self.project: Optional["Project"] = None
116
134
  self.arch = arch
117
135
  self.track_tmps = track_tmps
118
136
  self._canonical_size: int = canonical_size # TODO: Drop canonical_size
119
137
 
120
- self.register_definitions: MultiValuedMemory = (
138
+ self.registers: MultiValuedMemory = (
121
139
  MultiValuedMemory(
122
140
  memory_id="reg",
123
141
  top_func=self.top,
@@ -125,70 +143,76 @@ class LiveDefinitions:
125
143
  page_kwargs={"mo_cmp": self._mo_cmp},
126
144
  endness=self.arch.register_endness,
127
145
  )
128
- if register_definitions is None
129
- else register_definitions
146
+ if registers is None
147
+ else registers
130
148
  )
131
- self.stack_definitions: MultiValuedMemory = (
149
+ self.stack: MultiValuedMemory = (
132
150
  MultiValuedMemory(
133
151
  memory_id="mem",
134
152
  top_func=self.top,
135
153
  skip_missing_values_during_merging=False,
136
154
  page_kwargs={"mo_cmp": self._mo_cmp},
137
155
  )
138
- if stack_definitions is None
139
- else stack_definitions
156
+ if stack is None
157
+ else stack
140
158
  )
141
- self.memory_definitions: MultiValuedMemory = (
159
+ self.memory: MultiValuedMemory = (
142
160
  MultiValuedMemory(
143
161
  memory_id="mem",
144
162
  top_func=self.top,
145
163
  skip_missing_values_during_merging=False,
146
164
  page_kwargs={"mo_cmp": self._mo_cmp},
147
165
  )
148
- if memory_definitions is None
149
- else memory_definitions
166
+ if memory is None
167
+ else memory
150
168
  )
151
- self.heap_definitions: MultiValuedMemory = (
169
+ self.heap: MultiValuedMemory = (
152
170
  MultiValuedMemory(
153
171
  memory_id="mem",
154
172
  top_func=self.top,
155
173
  skip_missing_values_during_merging=False,
156
174
  page_kwargs={"mo_cmp": self._mo_cmp},
157
175
  )
158
- if heap_definitions is None
159
- else heap_definitions
176
+ if heap is None
177
+ else heap
160
178
  )
161
179
  self.tmps: Dict[int, Set[Definition]] = {} if tmps is None else tmps
180
+ self.others: Dict[Atom, MultiValues] = others if others is not None else {}
162
181
 
163
182
  # set state
164
- self.register_definitions.set_state(self)
165
- self.stack_definitions.set_state(self)
166
- self.memory_definitions.set_state(self)
167
- self.heap_definitions.set_state(self)
183
+ self.registers.set_state(self)
184
+ self.stack.set_state(self)
185
+ self.memory.set_state(self)
186
+ self.heap.set_state(self)
168
187
 
169
188
  self.register_uses = Uses() if register_uses is None else register_uses
170
189
  self.stack_uses = Uses() if stack_uses is None else stack_uses
171
190
  self.heap_uses = Uses() if heap_uses is None else heap_uses
172
191
  self.memory_uses = Uses() if memory_uses is None else memory_uses
173
192
  self.tmp_uses: Dict[int, Set[CodeLocation]] = defaultdict(set) if tmp_uses is None else tmp_uses
193
+ self.other_uses = Uses() if other_uses is None else other_uses
174
194
 
175
195
  self.uses_by_codeloc: Dict[CodeLocation, Set[Definition]] = defaultdict(set)
176
196
 
177
197
  @property
178
- def registers(self) -> MultiValuedMemory:
179
- return self.register_definitions
198
+ @deprecated("registers")
199
+ def register_definitions(self) -> MultiValuedMemory:
200
+ return self.registers
180
201
 
181
202
  @property
182
- def stack(self) -> MultiValuedMemory:
183
- return self.stack_definitions
203
+ @deprecated("stack")
204
+ def stack_definitions(self) -> MultiValuedMemory:
205
+ return self.stack
184
206
 
185
207
  @property
186
- def memory(self) -> MultiValuedMemory:
187
- return self.memory_definitions
208
+ @deprecated("memory")
209
+ def memory_definitions(self) -> MultiValuedMemory:
210
+ return self.memory
188
211
 
189
212
  @property
190
- def heap(self) -> MultiValuedMemory:
191
- return self.heap_definitions
213
+ @deprecated("heap")
214
+ def heap_definitions(self) -> MultiValuedMemory:
215
+ return self.heap
192
216
 
193
217
  def __repr__(self):
194
218
  ctnt = "LiveDefs"
@@ -201,18 +225,21 @@ class LiveDefinitions:
201
225
  self.arch,
202
226
  track_tmps=self.track_tmps,
203
227
  canonical_size=self._canonical_size,
204
- register_definitions=self.register_definitions.copy(),
205
- stack_definitions=self.stack_definitions.copy(),
206
- heap_definitions=self.heap_definitions.copy(),
207
- memory_definitions=self.memory_definitions.copy(),
228
+ registers=self.registers.copy(),
229
+ stack=self.stack.copy(),
230
+ heap=self.heap.copy(),
231
+ memory=self.memory.copy(),
208
232
  tmps=self.tmps.copy() if not discard_tmpdefs else None,
233
+ others=dict(self.others),
209
234
  register_uses=self.register_uses.copy(),
210
235
  stack_uses=self.stack_uses.copy(),
211
236
  heap_uses=self.heap_uses.copy(),
212
237
  memory_uses=self.memory_uses.copy(),
213
238
  tmp_uses=self.tmp_uses.copy() if not discard_tmpdefs else None,
239
+ other_uses=self.other_uses.copy(),
214
240
  )
215
241
 
242
+ rd.project = self.project
216
243
  return rd
217
244
 
218
245
  def reset_uses(self):
@@ -220,6 +247,7 @@ class LiveDefinitions:
220
247
  self.register_uses = Uses()
221
248
  self.memory_uses = Uses()
222
249
  self.heap_uses = Uses()
250
+ self.other_uses = Uses()
223
251
 
224
252
  def _get_weakref(self):
225
253
  return weakref.proxy(self)
@@ -283,7 +311,7 @@ class LiveDefinitions:
283
311
  return True
284
312
  return False
285
313
 
286
- def stack_address(self, offset: int) -> claripy.ast.Base:
314
+ def stack_address(self, offset: int) -> Optional[claripy.ast.bv.BV]:
287
315
  base = claripy.BVS("stack_base", self.arch.bits, explicit_name=True)
288
316
  if offset:
289
317
  return base + offset
@@ -353,7 +381,7 @@ class LiveDefinitions:
353
381
  Return the concrete value contained by the stack pointer.
354
382
  """
355
383
  assert self.arch.sp_offset is not None
356
- sp_values: MultiValues = self.register_definitions.load(self.arch.sp_offset, size=self.arch.bytes)
384
+ sp_values: MultiValues = self.registers.load(self.arch.sp_offset, size=self.arch.bytes)
357
385
  sp_v = sp_values.one_value()
358
386
  if sp_v is None:
359
387
  # multiple values of sp exists. still return a value if there is only one value (maybe with different
@@ -373,7 +401,7 @@ class LiveDefinitions:
373
401
  Return the offset of the stack pointer.
374
402
  """
375
403
  assert self.arch.sp_offset is not None
376
- sp_values: MultiValues = self.register_definitions.load(self.arch.sp_offset, size=self.arch.bytes)
404
+ sp_values: MultiValues = self.registers.load(self.arch.sp_offset, size=self.arch.bytes)
377
405
  sp_v = sp_values.one_value()
378
406
  if sp_v is None:
379
407
  values = [v for v in next(iter(sp_values.values())) if self.get_stack_offset(v) is not None]
@@ -401,21 +429,30 @@ class LiveDefinitions:
401
429
  raise ValueError("Unsupported architecture word size %d" % self.arch.bits)
402
430
  return (base_v + offset) & mask
403
431
 
404
- def merge(self, *others) -> Tuple["LiveDefinitions", bool]:
432
+ def merge(self, *others: "LiveDefinitions") -> Tuple["LiveDefinitions", bool]:
405
433
  state = self.copy()
406
434
 
407
- merge_occurred = state.register_definitions.merge([other.register_definitions for other in others], None)
408
- merge_occurred |= state.heap_definitions.merge([other.heap_definitions for other in others], None)
409
- merge_occurred |= state.memory_definitions.merge([other.memory_definitions for other in others], None)
410
- merge_occurred |= state.stack_definitions.merge([other.stack_definitions for other in others], None)
435
+ merge_occurred = state.registers.merge([other.registers for other in others], None)
436
+ merge_occurred |= state.heap.merge([other.heap for other in others], None)
437
+ merge_occurred |= state.memory.merge([other.memory for other in others], None)
438
+ merge_occurred |= state.stack.merge([other.stack for other in others], None)
411
439
 
412
440
  for other in others:
413
- other: LiveDefinitions
441
+ for k in other.others:
442
+ if k in self.others:
443
+ thing = self.others[k].merge(other.others[k])
444
+ if thing != self.others[k]:
445
+ merge_occurred = True
446
+ self.others[k] = thing
447
+ else:
448
+ self.others[k] = other.others[k]
449
+ merge_occurred = True
414
450
 
415
451
  merge_occurred |= state.register_uses.merge(other.register_uses)
416
452
  merge_occurred |= state.stack_uses.merge(other.stack_uses)
417
453
  merge_occurred |= state.heap_uses.merge(other.heap_uses)
418
454
  merge_occurred |= state.memory_uses.merge(other.memory_uses)
455
+ merge_occurred |= state.other_uses.merge(other.other_uses)
419
456
 
420
457
  return state, merge_occurred
421
458
 
@@ -429,21 +466,21 @@ class LiveDefinitions:
429
466
  """
430
467
 
431
468
  if isinstance(atom, Register):
432
- self.register_definitions.erase(atom.reg_offset, size=atom.size)
469
+ self.registers.erase(atom.reg_offset, size=atom.size)
433
470
  elif isinstance(atom, MemoryLocation):
434
471
  if isinstance(atom.addr, SpOffset):
435
472
  if atom.addr.offset is not None:
436
473
  stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
437
- self.stack_definitions.erase(stack_addr, size=atom.size)
474
+ self.stack.erase(stack_addr, size=atom.size)
438
475
  else:
439
476
  l.warning("Skip stack storing since the stack offset is None.")
440
477
  elif isinstance(atom.addr, HeapAddress):
441
- self.heap_definitions.erase(atom.addr.value, size=atom.size)
478
+ self.heap.erase(atom.addr.value, size=atom.size)
442
479
  elif isinstance(atom.addr, int):
443
- self.memory_definitions.erase(atom.addr, size=atom.size)
480
+ self.memory.erase(atom.addr, size=atom.size)
444
481
  elif isinstance(atom.addr, claripy.ast.Base):
445
482
  if atom.addr.concrete:
446
- self.memory_definitions.erase(atom.addr._model_concrete.value, size=atom.size)
483
+ self.memory.erase(atom.addr._model_concrete.value, size=atom.size)
447
484
  elif self.is_stack_address(atom.addr):
448
485
  stack_addr = self.get_stack_address(atom.addr)
449
486
  if stack_addr is None:
@@ -451,7 +488,7 @@ class LiveDefinitions:
451
488
  "Failed to convert stack address %s to a concrete stack address. Skip the store.", atom.addr
452
489
  )
453
490
  else:
454
- self.stack_definitions.erase(stack_addr, size=atom.size)
491
+ self.stack.erase(stack_addr, size=atom.size)
455
492
  else:
456
493
  return
457
494
  else:
@@ -459,7 +496,7 @@ class LiveDefinitions:
459
496
  elif isinstance(atom, Tmp):
460
497
  del self.tmps[atom.tmp_idx]
461
498
  else:
462
- raise NotImplementedError()
499
+ del self.others[atom]
463
500
 
464
501
  def kill_and_add_definition(
465
502
  self,
@@ -486,7 +523,7 @@ class LiveDefinitions:
486
523
  # set_object() replaces kill (not implemented) and add (add) in one step
487
524
  if isinstance(atom, Register):
488
525
  try:
489
- self.register_definitions.store(
526
+ self.registers.store(
490
527
  atom.reg_offset,
491
528
  d,
492
529
  size=atom.size,
@@ -501,16 +538,16 @@ class LiveDefinitions:
501
538
  if isinstance(atom.addr, SpOffset):
502
539
  if atom.addr.offset is not None:
503
540
  stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
504
- self.stack_definitions.store(stack_addr, d, size=atom.size, endness=endness)
541
+ self.stack.store(stack_addr, d, size=atom.size, endness=endness)
505
542
  else:
506
543
  l.warning("Skip stack storing since the stack offset is None.")
507
544
  elif isinstance(atom.addr, HeapAddress):
508
- self.heap_definitions.store(atom.addr.value, d, size=atom.size, endness=endness)
545
+ self.heap.store(atom.addr.value, d, size=atom.size, endness=endness)
509
546
  elif isinstance(atom.addr, int):
510
- self.memory_definitions.store(atom.addr, d, size=atom.size, endness=endness)
547
+ self.memory.store(atom.addr, d, size=atom.size, endness=endness)
511
548
  elif isinstance(atom.addr, claripy.ast.Base):
512
549
  if atom.addr.concrete:
513
- self.memory_definitions.store(atom.addr.concrete_value, d, size=atom.size, endness=endness)
550
+ self.memory.store(atom.addr.concrete_value, d, size=atom.size, endness=endness)
514
551
  elif self.is_stack_address(atom.addr):
515
552
  stack_addr = self.get_stack_address(atom.addr)
516
553
  if stack_addr is None:
@@ -518,7 +555,7 @@ class LiveDefinitions:
518
555
  "Failed to convert stack address %s to a concrete stack address. Skip the store.", atom.addr
519
556
  )
520
557
  else:
521
- self.stack_definitions.store(stack_addr, d, size=atom.size, endness=endness)
558
+ self.stack.store(stack_addr, d, size=atom.size, endness=endness)
522
559
  else:
523
560
  return None
524
561
  else:
@@ -530,7 +567,7 @@ class LiveDefinitions:
530
567
  self.tmps[atom.tmp_idx] = self.uses_by_codeloc[code_loc]
531
568
  return None
532
569
  else:
533
- raise NotImplementedError()
570
+ self.others[atom] = d
534
571
 
535
572
  return d
536
573
 
@@ -550,7 +587,9 @@ class LiveDefinitions:
550
587
  elif isinstance(atom, Tmp):
551
588
  self.add_tmp_use(atom, code_loc)
552
589
  else:
553
- raise TypeError("Unsupported atom type %s." % type(atom))
590
+ for defn in self.get_definitions(atom):
591
+ self.other_uses.add_use(defn, code_loc, expr)
592
+ self.uses_by_codeloc[code_loc].add(defn)
554
593
 
555
594
  def add_use_by_def(self, definition: Definition, code_loc: CodeLocation, expr: Any = None) -> None:
556
595
  if isinstance(definition.atom, Register):
@@ -571,24 +610,44 @@ class LiveDefinitions:
571
610
  # ignore constants
572
611
  pass
573
612
  else:
574
- raise TypeError("Unsupported atom type %s." % type(definition.atom))
613
+ self.other_uses.add_use(definition, code_loc, expr)
575
614
 
576
- def get_definitions(self, atom: Atom) -> Iterable[Definition]:
577
- if isinstance(atom, Register):
578
- yield from self.get_register_definitions(atom.reg_offset, atom.size)
579
- elif isinstance(atom, MemoryLocation):
580
- if isinstance(atom.addr, SpOffset):
581
- yield from self.get_stack_definitions(atom.addr.offset, atom.size, atom.endness)
582
- elif isinstance(atom.addr, HeapAddress):
583
- yield from self.get_heap_definitions(atom.addr.value, size=atom.size, endness=atom.endness)
584
- elif isinstance(atom.addr, int):
585
- yield from self.get_memory_definitions(atom.addr, atom.size, atom.endness)
615
+ def get_definitions(
616
+ self, thing: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]], MultiValues]
617
+ ) -> Iterable[Definition[Atom]]:
618
+ if isinstance(thing, MultiValues):
619
+ for vs in thing.values():
620
+ for v in vs:
621
+ for anno in v.annotations:
622
+ if isinstance(anno, DefinitionAnnotation):
623
+ yield anno.definition
624
+ return
625
+ elif isinstance(thing, Atom):
626
+ pass
627
+ elif isinstance(thing, Definition):
628
+ thing = thing.atom
629
+ else:
630
+ for atom2 in thing:
631
+ yield from self.get_definitions(atom2)
632
+ return
633
+
634
+ if isinstance(thing, Register):
635
+ yield from self.get_register_definitions(thing.reg_offset, thing.size)
636
+ elif isinstance(thing, MemoryLocation):
637
+ if isinstance(thing.addr, SpOffset):
638
+ yield from self.get_stack_definitions(thing.addr.offset, thing.size, thing.endness)
639
+ elif isinstance(thing.addr, HeapAddress):
640
+ yield from self.get_heap_definitions(thing.addr.value, size=thing.size, endness=thing.endness)
641
+ elif isinstance(thing.addr, int):
642
+ yield from self.get_memory_definitions(thing.addr, thing.size, thing.endness)
586
643
  else:
587
644
  return
588
- elif isinstance(atom, Tmp):
589
- yield from self.get_tmp_definitions(atom.tmp_idx)
645
+ elif isinstance(thing, Tmp):
646
+ yield from self.get_tmp_definitions(thing.tmp_idx)
590
647
  else:
591
- raise TypeError("Unsupported atom type %s." % type(atom))
648
+ for mvs in self.others.get(thing, {}).values():
649
+ for mv in mvs:
650
+ yield from self.get_definitions(mv)
592
651
 
593
652
  def get_tmp_definitions(self, tmp_idx: int) -> Iterable[Definition]:
594
653
  if tmp_idx in self.tmps:
@@ -598,7 +657,7 @@ class LiveDefinitions:
598
657
 
599
658
  def get_register_definitions(self, reg_offset: int, size: int, endness=None) -> Iterable[Definition]:
600
659
  try:
601
- values: MultiValues = self.register_definitions.load(
660
+ values: MultiValues = self.registers.load(
602
661
  reg_offset,
603
662
  size=size,
604
663
  endness=endness,
@@ -606,7 +665,7 @@ class LiveDefinitions:
606
665
  except SimMemoryMissingError as ex:
607
666
  # load values and stop at the missing location
608
667
  if ex.missing_addr > reg_offset:
609
- values: MultiValues = self.register_definitions.load(
668
+ values: MultiValues = self.registers.load(
610
669
  reg_offset, size=ex.missing_addr - reg_offset, endness=endness
611
670
  )
612
671
  else:
@@ -617,7 +676,7 @@ class LiveDefinitions:
617
676
  def get_stack_values(self, stack_offset: int, size: int, endness: str) -> Optional[MultiValues]:
618
677
  stack_addr = self.stack_offset_to_stack_addr(stack_offset)
619
678
  try:
620
- return self.stack_definitions.load(stack_addr, size=size, endness=endness)
679
+ return self.stack.load(stack_addr, size=size, endness=endness)
621
680
  except SimMemoryMissingError:
622
681
  return None
623
682
 
@@ -629,54 +688,59 @@ class LiveDefinitions:
629
688
 
630
689
  def get_heap_definitions(self, heap_addr: int, size: int, endness) -> Iterable[Definition]:
631
690
  try:
632
- mv: MultiValues = self.heap_definitions.load(heap_addr, size=size, endness=endness)
691
+ mv: MultiValues = self.heap.load(heap_addr, size=size, endness=endness)
633
692
  except SimMemoryMissingError:
634
693
  return
635
694
  yield from LiveDefinitions.extract_defs_from_mv(mv)
636
695
 
637
696
  def get_memory_definitions(self, addr: int, size: int, endness) -> Iterable[Definition]:
638
697
  try:
639
- values = self.memory_definitions.load(addr, size=size, endness=endness)
698
+ values = self.memory.load(addr, size=size, endness=endness)
640
699
  except SimMemoryMissingError:
641
700
  return
642
701
  yield from LiveDefinitions.extract_defs_from_mv(values)
643
702
 
703
+ @deprecated("get_definitions")
644
704
  def get_definitions_from_atoms(self, atoms: Iterable[Atom]) -> Iterable[Definition]:
645
705
  result = set()
646
706
  for atom in atoms:
647
707
  result |= set(self.get_definitions(atom))
648
708
  return result
649
709
 
710
+ @deprecated("get_values")
650
711
  def get_value_from_definition(self, definition: Definition) -> Optional[MultiValues]:
651
712
  return self.get_value_from_atom(definition.atom)
652
713
 
653
- def get_one_value_from_definition(self, definition: Definition) -> Optional[claripy.ast.base.Base]:
714
+ @deprecated("get_one_value")
715
+ def get_one_value_from_definition(self, definition: Definition) -> Optional[claripy.ast.bv.BV]:
654
716
  return self.get_one_value_from_atom(definition.atom)
655
717
 
718
+ @deprecated("get_concrete_value")
656
719
  def get_concrete_value_from_definition(self, definition: Definition) -> Optional[int]:
657
720
  return self.get_concrete_value_from_atom(definition.atom)
658
721
 
722
+ @deprecated("get_values")
659
723
  def get_value_from_atom(self, atom: Atom) -> Optional[MultiValues]:
660
724
  if isinstance(atom, Register):
661
725
  try:
662
- return self.register_definitions.load(atom.reg_offset, size=atom.size)
726
+ return self.registers.load(atom.reg_offset, size=atom.size)
663
727
  except SimMemoryMissingError:
664
728
  return None
665
729
  elif isinstance(atom, MemoryLocation):
666
730
  if isinstance(atom.addr, SpOffset):
667
731
  stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
668
732
  try:
669
- return self.stack_definitions.load(stack_addr, size=atom.size, endness=atom.endness)
733
+ return self.stack.load(stack_addr, size=atom.size, endness=atom.endness)
670
734
  except SimMemoryMissingError:
671
735
  return None
672
736
  elif isinstance(atom.addr, HeapAddress):
673
737
  try:
674
- return self.heap_definitions.load(atom.addr.value, size=atom.size, endness=atom.endness)
738
+ return self.heap.load(atom.addr.value, size=atom.size, endness=atom.endness)
675
739
  except SimMemoryMissingError:
676
740
  return None
677
741
  elif isinstance(atom.addr, int):
678
742
  try:
679
- return self.memory_definitions.load(atom.addr, size=atom.size, endness=atom.endness)
743
+ return self.memory.load(atom.addr, size=atom.size, endness=atom.endness)
680
744
  except SimMemoryMissingError:
681
745
  return None
682
746
  else:
@@ -685,12 +749,14 @@ class LiveDefinitions:
685
749
  else:
686
750
  return None
687
751
 
688
- def get_one_value_from_atom(self, atom: Atom) -> Optional[claripy.ast.BV]:
752
+ @deprecated("get_one_value")
753
+ def get_one_value_from_atom(self, atom: Atom) -> Optional[claripy.ast.bv.BV]:
689
754
  r = self.get_value_from_atom(atom)
690
755
  if r is None:
691
756
  return None
692
757
  return r.one_value()
693
758
 
759
+ @deprecated("get_concrete_value")
694
760
  def get_concrete_value_from_atom(self, atom: Atom) -> Optional[int]:
695
761
  r = self.get_one_value_from_atom(atom)
696
762
  if r is None:
@@ -699,28 +765,106 @@ class LiveDefinitions:
699
765
  return None
700
766
  return r.concrete_value
701
767
 
702
- def get_values(self, spec: Union[Atom, Definition]) -> Optional[MultiValues]:
703
- if isinstance(spec, Atom):
704
- return self.get_value_from_atom(spec)
768
+ def get_values(
769
+ self, spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]]
770
+ ) -> Optional[MultiValues]:
771
+ if isinstance(spec, Definition):
772
+ atom = spec.atom
773
+ elif isinstance(spec, Atom):
774
+ atom = spec
705
775
  else:
706
- return self.get_value_from_definition(spec)
776
+ result = None
777
+ for atom in spec:
778
+ r = self.get_values(atom)
779
+ if r is None:
780
+ continue
781
+ if result is None:
782
+ result = r
783
+ else:
784
+ result = result.merge(r)
785
+ return result
707
786
 
708
- def get_one_value(self, spec: Union[Atom, Definition]) -> Optional[claripy.ast.base.Base]:
709
- if isinstance(spec, Atom):
710
- return self.get_one_value_from_atom(spec)
787
+ if isinstance(atom, Register):
788
+ try:
789
+ return self.registers.load(atom.reg_offset, size=atom.size)
790
+ except SimMemoryMissingError:
791
+ return None
792
+ elif isinstance(atom, MemoryLocation):
793
+ if isinstance(atom.addr, SpOffset):
794
+ stack_addr = self.stack_offset_to_stack_addr(atom.addr.offset)
795
+ try:
796
+ return self.stack.load(stack_addr, size=atom.size, endness=atom.endness)
797
+ except SimMemoryMissingError:
798
+ return None
799
+ elif isinstance(atom.addr, HeapAddress):
800
+ try:
801
+ return self.heap.load(atom.addr.value, size=atom.size, endness=atom.endness)
802
+ except SimMemoryMissingError:
803
+ return None
804
+ elif isinstance(atom.addr, int):
805
+ try:
806
+ return self.memory.load(atom.addr, size=atom.size, endness=atom.endness)
807
+ except SimMemoryMissingError:
808
+ pass
809
+ if self.project is not None:
810
+ try:
811
+ bytestring = self.project.loader.memory.load(atom.addr, atom.size)
812
+ if atom.endness == archinfo.Endness.LE:
813
+ bytestring = bytes(reversed(bytestring))
814
+ mv = MultiValues(
815
+ self.annotate_with_def(claripy.BVV(bytestring), Definition(atom, ExternalCodeLocation()))
816
+ )
817
+ return mv
818
+ except KeyError:
819
+ pass
820
+ return None
821
+ else:
822
+ # ignore RegisterOffset
823
+ return None
711
824
  else:
712
- return self.get_one_value_from_definition(spec)
825
+ return self.others.get(atom, None)
713
826
 
714
- def get_concrete_value(self, spec: Union[Atom, Definition]) -> Optional[int]:
715
- if isinstance(spec, Atom):
716
- return self.get_concrete_value_from_atom(spec)
717
- else:
718
- return self.get_concrete_value_from_definition(spec)
827
+ def get_one_value(
828
+ self, spec: Union[Atom, Definition, Iterable[Atom], Iterable[Definition[Atom]]]
829
+ ) -> Optional[claripy.ast.bv.BV]:
830
+ r = self.get_values(spec)
831
+ if r is None:
832
+ return None
833
+ return r.one_value()
834
+
835
+ @overload
836
+ def get_concrete_value(
837
+ self, spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]], cast_to: Type[int] = ...
838
+ ) -> Optional[int]:
839
+ ...
840
+
841
+ @overload
842
+ def get_concrete_value(
843
+ self,
844
+ spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]],
845
+ cast_to: Type[bytes] = ...,
846
+ ) -> Optional[bytes]:
847
+ ...
848
+
849
+ def get_concrete_value(
850
+ self,
851
+ spec: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]]],
852
+ cast_to: Union[Type[int], Type[bytes]] = int,
853
+ ) -> Union[int, bytes, None]:
854
+ r = self.get_one_value(spec)
855
+ if r is None:
856
+ return None
857
+ if r.symbolic:
858
+ return None
859
+ result = r.concrete_value
860
+ if issubclass(cast_to, bytes):
861
+ return result.to_bytes(len(r) // 8, "big")
862
+ return result
719
863
 
720
864
  def add_register_use(self, reg_offset: int, size: int, code_loc: CodeLocation, expr: Optional[Any] = None) -> None:
721
865
  # get all current definitions
722
866
  try:
723
- mvs: MultiValues = self.register_definitions.load(reg_offset, size=size)
867
+ mvs: MultiValues = self.registers.load(reg_offset, size=size)
724
868
  except SimMemoryMissingError:
725
869
  return
726
870
 
@@ -787,3 +931,103 @@ class LiveDefinitions:
787
931
 
788
932
  self.tmp_uses[def_.atom.tmp_idx].add(code_loc)
789
933
  self.uses_by_codeloc[code_loc].add(def_)
934
+
935
+ @overload
936
+ def deref(
937
+ self,
938
+ pointer: Union[MultiValues, Atom, Definition, Iterable[Atom], Iterable[Definition]],
939
+ size: Union[int, DerefSize],
940
+ endness: archinfo.Endness = ...,
941
+ ) -> Set[MemoryLocation]:
942
+ ...
943
+
944
+ @overload
945
+ def deref(
946
+ self,
947
+ pointer: Union[int, claripy.ast.BV, HeapAddress, SpOffset],
948
+ size: Union[int, DerefSize],
949
+ endness: archinfo.Endness = ...,
950
+ ) -> Optional[MemoryLocation]:
951
+ ...
952
+
953
+ def deref(self, pointer, size, endness=archinfo.Endness.BE):
954
+ if isinstance(pointer, (Atom, Definition)):
955
+ pointer = self.get_values(pointer)
956
+ if pointer is None:
957
+ return set()
958
+
959
+ if isinstance(pointer, set):
960
+ result = set()
961
+ for ptr_atom in pointer:
962
+ result.update(self.deref(ptr_atom, size, endness))
963
+ return result
964
+
965
+ if isinstance(pointer, MultiValues):
966
+ result = set()
967
+ for vs in pointer.values():
968
+ for value in vs:
969
+ atom = self.deref(value, size, endness)
970
+ if atom is not None:
971
+ result.add(atom)
972
+ return result
973
+
974
+ if isinstance(pointer, (HeapAddress, SpOffset, int)):
975
+ addr = pointer
976
+ else:
977
+ assert isinstance(pointer, claripy.ast.BV)
978
+ if self.is_top(pointer):
979
+ return None
980
+
981
+ # TODO this can be simplified with the walrus operator
982
+ stack_offset = self.get_stack_offset(pointer)
983
+ if stack_offset is not None:
984
+ addr = SpOffset(len(pointer), stack_offset)
985
+ else:
986
+ heap_offset = self.get_heap_offset(pointer)
987
+ if heap_offset is not None:
988
+ addr = HeapAddress(heap_offset)
989
+ elif pointer.op == "BVV":
990
+ addr = pointer.args[0]
991
+ else:
992
+ # cannot resolve
993
+ return None
994
+
995
+ if isinstance(size, DerefSize):
996
+ assert size == DerefSize.NULL_TERMINATE
997
+ for sz in range(4096): # arbitrary
998
+ # truly evil that this is an abstraction we have to contend with
999
+ mv = self.get_values(MemoryLocation(addr + sz, 1, endness))
1000
+ if mv is not None and 0 in mv and any(one.op == "BVV" and one.args[0] == 0 for one in mv[0]):
1001
+ size = sz + 1
1002
+ break
1003
+ else:
1004
+ l.warning(
1005
+ "Could not resolve cstring dereference at %s to a concrete size",
1006
+ hex(addr) if isinstance(addr, int) else addr,
1007
+ )
1008
+ size = 4096
1009
+
1010
+ return MemoryLocation(addr, size, endness)
1011
+
1012
+ @staticmethod
1013
+ def is_heap_address(addr: claripy.ast.Base) -> bool:
1014
+ return "heap_base" in addr.variables
1015
+
1016
+ @staticmethod
1017
+ def get_heap_offset(addr: claripy.ast.Base) -> Optional[int]:
1018
+ if "heap_base" in addr.variables:
1019
+ if addr.op == "BVS":
1020
+ return 0
1021
+ elif addr.op == "__add__" and len(addr.args) == 2 and addr.args[1].op == "BVV":
1022
+ return addr.args[1]._model_concrete.value
1023
+ return None
1024
+
1025
+ def heap_address(self, offset: Union[int, HeapAddress]) -> claripy.ast.BV:
1026
+ if isinstance(offset, HeapAddress):
1027
+ if not isinstance(offset.value, int):
1028
+ raise TypeError("TODO: what's this? contact @rhelmot")
1029
+ offset = offset.value
1030
+ base = claripy.BVS("heap_base", self.arch.bits, explicit_name=True)
1031
+ if offset:
1032
+ return base + offset
1033
+ return base