angr 9.2.111__py3-none-manylinux2014_aarch64.whl → 9.2.113__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.
- angr/__init__.py +1 -1
- angr/analyses/cfg/cfg_base.py +4 -1
- angr/analyses/decompiler/condition_processor.py +9 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -1
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +367 -0
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +99 -12
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +79 -9
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +21 -0
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +111 -9
- angr/analyses/decompiler/redundant_label_remover.py +17 -0
- angr/analyses/decompiler/seq_cf_structure_counter.py +37 -0
- angr/analyses/decompiler/structured_codegen/c.py +4 -5
- angr/analyses/decompiler/structuring/phoenix.py +3 -3
- angr/analyses/reaching_definitions/rd_state.py +2 -0
- angr/analyses/reaching_definitions/reaching_definitions.py +7 -0
- angr/angrdb/serializers/loader.py +91 -7
- angr/calling_conventions.py +11 -9
- angr/knowledge_plugins/key_definitions/live_definitions.py +5 -0
- angr/knowledge_plugins/propagations/states.py +3 -2
- angr/knowledge_plugins/variables/variable_manager.py +1 -1
- angr/procedures/stubs/ReturnUnconstrained.py +1 -2
- angr/procedures/stubs/syscall_stub.py +1 -2
- angr/sim_type.py +354 -136
- angr/state_plugins/debug_variables.py +2 -2
- angr/state_plugins/solver.py +5 -13
- angr/storage/memory_mixins/multi_value_merger_mixin.py +13 -3
- angr/utils/orderedset.py +70 -0
- angr/vaults.py +0 -1
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/METADATA +6 -6
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/RECORD +35 -32
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/WHEEL +1 -1
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/LICENSE +0 -0
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/entry_points.txt +0 -0
- {angr-9.2.111.dist-info → angr-9.2.113.dist-info}/top_level.txt +0 -0
angr/sim_type.py
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
# pylint:disable=abstract-method,line-too-long,missing-class-docstring
|
|
1
|
+
# pylint:disable=abstract-method,line-too-long,missing-class-docstring,wrong-import-position
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
from collections import OrderedDict, defaultdict, ChainMap
|
|
5
6
|
import copy
|
|
6
7
|
import re
|
|
7
|
-
from typing import Any, TYPE_CHECKING
|
|
8
|
+
from typing import Literal, Optional, Any, Union, TYPE_CHECKING, cast, overload
|
|
9
|
+
from collections.abc import Iterable
|
|
8
10
|
import logging
|
|
9
11
|
|
|
10
|
-
try:
|
|
11
|
-
import pycparser
|
|
12
|
-
except ImportError:
|
|
13
|
-
pycparser = None
|
|
14
|
-
|
|
15
12
|
try:
|
|
16
13
|
import CppHeaderParser
|
|
17
14
|
except ImportError:
|
|
18
15
|
CppHeaderParser = None
|
|
19
16
|
|
|
20
|
-
from archinfo import Endness
|
|
17
|
+
from archinfo import Endness, Arch
|
|
21
18
|
import claripy
|
|
22
19
|
|
|
23
|
-
from angr.errors import AngrMissingTypeError
|
|
20
|
+
from angr.errors import AngrMissingTypeError, AngrTypeError
|
|
24
21
|
from .misc.ux import deprecated
|
|
25
22
|
|
|
26
23
|
if TYPE_CHECKING:
|
|
24
|
+
import pycparser
|
|
27
25
|
from angr.procedures.definitions import SimTypeCollection
|
|
26
|
+
from angr.storage.memory_mixins import _Coerce
|
|
27
|
+
|
|
28
|
+
StoreType = Union[_Coerce, claripy.ast.BV]
|
|
29
|
+
else:
|
|
30
|
+
try:
|
|
31
|
+
import pycparser
|
|
32
|
+
except ImportError:
|
|
33
|
+
pycparser = None
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
l = logging.getLogger(name=__name__)
|
|
@@ -39,18 +45,19 @@ class SimType:
|
|
|
39
45
|
SimType exists to track type information for SimProcedures.
|
|
40
46
|
"""
|
|
41
47
|
|
|
42
|
-
_fields = ()
|
|
43
|
-
_arch
|
|
44
|
-
_size = None
|
|
45
|
-
_can_refine_int = False
|
|
46
|
-
_base_name
|
|
47
|
-
base = True
|
|
48
|
+
_fields: tuple[str, ...] = ()
|
|
49
|
+
_arch: Arch | None
|
|
50
|
+
_size: int | None = None
|
|
51
|
+
_can_refine_int: bool = False
|
|
52
|
+
_base_name: str
|
|
53
|
+
base: bool = True
|
|
48
54
|
|
|
49
55
|
def __init__(self, label=None):
|
|
50
56
|
"""
|
|
51
57
|
:param label: the type label.
|
|
52
58
|
"""
|
|
53
59
|
self.label = label
|
|
60
|
+
self._arch = None
|
|
54
61
|
|
|
55
62
|
@staticmethod
|
|
56
63
|
def _simtype_eq(self_type: SimType, other: SimType, avoid: dict[str, set[SimType]] | None) -> bool:
|
|
@@ -106,13 +113,11 @@ class SimType:
|
|
|
106
113
|
raise KeyError(f"{k} is not a valid refinement")
|
|
107
114
|
|
|
108
115
|
@property
|
|
109
|
-
def size(self):
|
|
116
|
+
def size(self) -> int | None:
|
|
110
117
|
"""
|
|
111
|
-
The size of the type in bits.
|
|
118
|
+
The size of the type in bits, or None if no size is computable.
|
|
112
119
|
"""
|
|
113
|
-
|
|
114
|
-
return self._size
|
|
115
|
-
return NotImplemented
|
|
120
|
+
return self._size
|
|
116
121
|
|
|
117
122
|
@property
|
|
118
123
|
def alignment(self):
|
|
@@ -121,11 +126,11 @@ class SimType:
|
|
|
121
126
|
"""
|
|
122
127
|
if self._arch is None:
|
|
123
128
|
raise ValueError("Can't tell my alignment without an arch!")
|
|
124
|
-
if self.size is
|
|
125
|
-
|
|
129
|
+
if self.size is None:
|
|
130
|
+
raise AngrTypeError("Cannot compute the alignment of a type with no size")
|
|
126
131
|
return self.size // self._arch.byte_width
|
|
127
132
|
|
|
128
|
-
def with_arch(self, arch):
|
|
133
|
+
def with_arch(self, arch: Arch | None):
|
|
129
134
|
if arch is None:
|
|
130
135
|
return self
|
|
131
136
|
if self._arch is not None and self._arch == arch:
|
|
@@ -141,7 +146,9 @@ class SimType:
|
|
|
141
146
|
def _init_str(self):
|
|
142
147
|
return f"NotImplemented({self.__class__.__name__})"
|
|
143
148
|
|
|
144
|
-
def c_repr(
|
|
149
|
+
def c_repr(
|
|
150
|
+
self, name=None, full=0, memo=None, indent: int | None = 0, name_parens: bool = True
|
|
151
|
+
): # pylint: disable=unused-argument
|
|
145
152
|
if name is None:
|
|
146
153
|
return repr(self)
|
|
147
154
|
else:
|
|
@@ -150,7 +157,13 @@ class SimType:
|
|
|
150
157
|
def copy(self):
|
|
151
158
|
raise NotImplementedError()
|
|
152
159
|
|
|
153
|
-
def
|
|
160
|
+
def extract(self, state: SimState, addr, concrete: bool = False) -> Any:
|
|
161
|
+
raise NotImplementedError
|
|
162
|
+
|
|
163
|
+
def store(self, state: SimState, addr, value: Any):
|
|
164
|
+
raise NotImplementedError
|
|
165
|
+
|
|
166
|
+
def extract_claripy(self, bits) -> Any:
|
|
154
167
|
"""
|
|
155
168
|
Given a bitvector `bits` which was loaded from memory in a big-endian fashion, return a more appropriate or
|
|
156
169
|
structured representation of the data.
|
|
@@ -172,6 +185,15 @@ class TypeRef(SimType):
|
|
|
172
185
|
self.type = ty
|
|
173
186
|
self._name = name
|
|
174
187
|
|
|
188
|
+
@property
|
|
189
|
+
def type(self):
|
|
190
|
+
return self._type
|
|
191
|
+
|
|
192
|
+
@type.setter
|
|
193
|
+
def type(self, val):
|
|
194
|
+
self._type = val
|
|
195
|
+
self._arch = val._arch
|
|
196
|
+
|
|
175
197
|
@property
|
|
176
198
|
def name(self):
|
|
177
199
|
"""
|
|
@@ -189,10 +211,6 @@ class TypeRef(SimType):
|
|
|
189
211
|
def __repr__(self):
|
|
190
212
|
return self.name
|
|
191
213
|
|
|
192
|
-
@property
|
|
193
|
-
def _arch(self):
|
|
194
|
-
return self.type._arch
|
|
195
|
-
|
|
196
214
|
@property
|
|
197
215
|
def size(self):
|
|
198
216
|
return self.type.size
|
|
@@ -278,7 +296,7 @@ class SimTypeTop(SimType):
|
|
|
278
296
|
|
|
279
297
|
_fields = ("size",)
|
|
280
298
|
|
|
281
|
-
def __init__(self, size=None, label=None):
|
|
299
|
+
def __init__(self, size: int | None = None, label=None):
|
|
282
300
|
SimType.__init__(self, label)
|
|
283
301
|
self._size = size
|
|
284
302
|
|
|
@@ -296,7 +314,7 @@ class SimTypeReg(SimType):
|
|
|
296
314
|
|
|
297
315
|
_fields = ("size",)
|
|
298
316
|
|
|
299
|
-
def __init__(self, size, label=None):
|
|
317
|
+
def __init__(self, size: int | None, label=None):
|
|
300
318
|
"""
|
|
301
319
|
:param label: the type label.
|
|
302
320
|
:param size: the size of the type (e.g. 32bit, 8bit, etc.).
|
|
@@ -307,19 +325,10 @@ class SimTypeReg(SimType):
|
|
|
307
325
|
def __repr__(self):
|
|
308
326
|
return f"reg{self.size}_t"
|
|
309
327
|
|
|
310
|
-
def
|
|
311
|
-
# TODO: EDG says this looks dangerously closed-minded. Just in case...
|
|
312
|
-
assert self.size % state.arch.byte_width == 0
|
|
313
|
-
|
|
314
|
-
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
315
|
-
if not concrete:
|
|
316
|
-
return out
|
|
317
|
-
return state.solver.eval(out)
|
|
318
|
-
|
|
319
|
-
def store(self, state, addr, value):
|
|
328
|
+
def store(self, state, addr, value: StoreType):
|
|
320
329
|
store_endness = state.arch.memory_endness
|
|
321
330
|
try:
|
|
322
|
-
value = value.ast
|
|
331
|
+
value = value.ast # type: ignore
|
|
323
332
|
except AttributeError:
|
|
324
333
|
pass
|
|
325
334
|
if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
|
|
@@ -345,7 +354,7 @@ class SimTypeNum(SimType):
|
|
|
345
354
|
|
|
346
355
|
_fields = SimType._fields + ("signed", "size")
|
|
347
356
|
|
|
348
|
-
def __init__(self, size, signed=True, label=None):
|
|
357
|
+
def __init__(self, size: int, signed=True, label=None):
|
|
349
358
|
"""
|
|
350
359
|
:param size: The size of the integer, in bits
|
|
351
360
|
:param signed: Whether the integer is signed or not
|
|
@@ -355,9 +364,20 @@ class SimTypeNum(SimType):
|
|
|
355
364
|
self._size = size
|
|
356
365
|
self.signed = signed
|
|
357
366
|
|
|
367
|
+
@property
|
|
368
|
+
def size(self) -> int:
|
|
369
|
+
assert self._size is not None
|
|
370
|
+
return self._size
|
|
371
|
+
|
|
358
372
|
def __repr__(self):
|
|
359
373
|
return "{}int{}_t".format("" if self.signed else "u", self.size)
|
|
360
374
|
|
|
375
|
+
@overload
|
|
376
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
377
|
+
|
|
378
|
+
@overload
|
|
379
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
380
|
+
|
|
361
381
|
def extract(self, state, addr, concrete=False):
|
|
362
382
|
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
363
383
|
if not concrete:
|
|
@@ -367,14 +387,14 @@ class SimTypeNum(SimType):
|
|
|
367
387
|
n -= 1 << (self.size)
|
|
368
388
|
return n
|
|
369
389
|
|
|
370
|
-
def store(self, state, addr, value):
|
|
390
|
+
def store(self, state, addr, value: StoreType):
|
|
371
391
|
store_endness = state.arch.memory_endness
|
|
372
392
|
|
|
373
393
|
if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
|
|
374
394
|
if value.size() != self.size:
|
|
375
395
|
raise ValueError("size of expression is wrong size for type")
|
|
376
|
-
elif isinstance(value, int):
|
|
377
|
-
value =
|
|
396
|
+
elif isinstance(value, int) and self.size is not None:
|
|
397
|
+
value = claripy.BVV(value, self.size)
|
|
378
398
|
elif isinstance(value, bytes):
|
|
379
399
|
store_endness = "Iend_BE"
|
|
380
400
|
else:
|
|
@@ -426,8 +446,14 @@ class SimTypeInt(SimTypeReg):
|
|
|
426
446
|
raise ValueError("Can't tell my size without an arch!")
|
|
427
447
|
try:
|
|
428
448
|
return self._arch.sizeof[self._base_name]
|
|
429
|
-
except KeyError as
|
|
430
|
-
raise ValueError(f"Arch {self._arch.name} doesn't have its {self._base_name} type defined!") from
|
|
449
|
+
except KeyError as e:
|
|
450
|
+
raise ValueError(f"Arch {self._arch.name} doesn't have its {self._base_name} type defined!") from e
|
|
451
|
+
|
|
452
|
+
@overload
|
|
453
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
454
|
+
|
|
455
|
+
@overload
|
|
456
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
431
457
|
|
|
432
458
|
def extract(self, state, addr, concrete=False):
|
|
433
459
|
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
@@ -488,13 +514,13 @@ class SimTypeChar(SimTypeReg):
|
|
|
488
514
|
:param label: the type label.
|
|
489
515
|
"""
|
|
490
516
|
# FIXME: Now the size of a char is state-dependent.
|
|
491
|
-
|
|
517
|
+
super().__init__(8, label=label)
|
|
492
518
|
self.signed = signed
|
|
493
519
|
|
|
494
|
-
def __repr__(self):
|
|
520
|
+
def __repr__(self) -> str:
|
|
495
521
|
return "char"
|
|
496
522
|
|
|
497
|
-
def store(self, state, addr, value):
|
|
523
|
+
def store(self, state, addr, value: StoreType):
|
|
498
524
|
# FIXME: This is a hack.
|
|
499
525
|
self._size = state.arch.byte_width
|
|
500
526
|
try:
|
|
@@ -506,13 +532,19 @@ class SimTypeChar(SimTypeReg):
|
|
|
506
532
|
else:
|
|
507
533
|
raise
|
|
508
534
|
|
|
509
|
-
|
|
535
|
+
@overload
|
|
536
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
537
|
+
|
|
538
|
+
@overload
|
|
539
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> bytes: ...
|
|
540
|
+
|
|
541
|
+
def extract(self, state, addr, concrete: bool = False) -> claripy.ast.BV | bytes:
|
|
510
542
|
# FIXME: This is a hack.
|
|
511
543
|
self._size = state.arch.byte_width
|
|
512
544
|
|
|
513
|
-
out =
|
|
545
|
+
out = state.memory.load(addr, 1, endness=state.arch.memory_endness)
|
|
514
546
|
if concrete:
|
|
515
|
-
return bytes([out])
|
|
547
|
+
return bytes(cast(list[int], [state.solver.eval(out)]))
|
|
516
548
|
return out
|
|
517
549
|
|
|
518
550
|
def _init_str(self):
|
|
@@ -542,7 +574,7 @@ class SimTypeWideChar(SimTypeReg):
|
|
|
542
574
|
def __repr__(self):
|
|
543
575
|
return "wchar"
|
|
544
576
|
|
|
545
|
-
def store(self, state, addr, value):
|
|
577
|
+
def store(self, state, addr, value: StoreType):
|
|
546
578
|
self._size = state.arch.byte_width
|
|
547
579
|
try:
|
|
548
580
|
super().store(state, addr, value)
|
|
@@ -553,7 +585,7 @@ class SimTypeWideChar(SimTypeReg):
|
|
|
553
585
|
else:
|
|
554
586
|
raise
|
|
555
587
|
|
|
556
|
-
def extract(self, state, addr, concrete=False):
|
|
588
|
+
def extract(self, state, addr, concrete=False) -> Any:
|
|
557
589
|
self._size = state.arch.byte_width
|
|
558
590
|
|
|
559
591
|
out = super().extract(state, addr, concrete)
|
|
@@ -571,14 +603,30 @@ class SimTypeWideChar(SimTypeReg):
|
|
|
571
603
|
return self.__class__(signed=self.signed, label=self.label)
|
|
572
604
|
|
|
573
605
|
|
|
574
|
-
class SimTypeBool(
|
|
606
|
+
class SimTypeBool(SimTypeReg):
|
|
575
607
|
_base_name = "bool"
|
|
576
608
|
|
|
609
|
+
def __init__(self, signed=True, label=None):
|
|
610
|
+
"""
|
|
611
|
+
:param label: the type label.
|
|
612
|
+
"""
|
|
613
|
+
# FIXME: Now the size of a char is state-dependent.
|
|
614
|
+
super().__init__(8, label=label)
|
|
615
|
+
self.signed = signed
|
|
616
|
+
|
|
577
617
|
def __repr__(self):
|
|
578
618
|
return "bool"
|
|
579
619
|
|
|
580
|
-
def store(self, state, addr, value):
|
|
581
|
-
|
|
620
|
+
def store(self, state, addr, value: StoreType | bool):
|
|
621
|
+
if isinstance(value, bool):
|
|
622
|
+
value = int(value)
|
|
623
|
+
return super().store(state, addr, value)
|
|
624
|
+
|
|
625
|
+
@overload
|
|
626
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.Bool: ...
|
|
627
|
+
|
|
628
|
+
@overload
|
|
629
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> bool: ...
|
|
582
630
|
|
|
583
631
|
def extract(self, state, addr, concrete=False):
|
|
584
632
|
ver = super().extract(state, addr, concrete)
|
|
@@ -589,6 +637,9 @@ class SimTypeBool(SimTypeChar):
|
|
|
589
637
|
def _init_str(self):
|
|
590
638
|
return f"{self.__class__.__name__}()"
|
|
591
639
|
|
|
640
|
+
def copy(self):
|
|
641
|
+
return self.__class__(signed=self.signed, label=self.label)
|
|
642
|
+
|
|
592
643
|
|
|
593
644
|
class SimTypeFd(SimTypeReg):
|
|
594
645
|
"""
|
|
@@ -605,6 +656,10 @@ class SimTypeFd(SimTypeReg):
|
|
|
605
656
|
# TODO: That's so closed-minded!
|
|
606
657
|
super().__init__(32, label=label)
|
|
607
658
|
|
|
659
|
+
@property
|
|
660
|
+
def size(self):
|
|
661
|
+
return 32
|
|
662
|
+
|
|
608
663
|
def __repr__(self):
|
|
609
664
|
return "fd_t"
|
|
610
665
|
|
|
@@ -617,6 +672,21 @@ class SimTypeFd(SimTypeReg):
|
|
|
617
672
|
('label="%s"' % self.label) if self.label is not None else "",
|
|
618
673
|
)
|
|
619
674
|
|
|
675
|
+
@overload
|
|
676
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
677
|
+
|
|
678
|
+
@overload
|
|
679
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
680
|
+
|
|
681
|
+
def extract(self, state, addr, concrete=False):
|
|
682
|
+
# TODO: EDG says this looks dangerously closed-minded. Just in case...
|
|
683
|
+
assert self.size % state.arch.byte_width == 0
|
|
684
|
+
|
|
685
|
+
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
686
|
+
if not concrete:
|
|
687
|
+
return out
|
|
688
|
+
return state.solver.eval(out)
|
|
689
|
+
|
|
620
690
|
|
|
621
691
|
class SimTypePointer(SimTypeReg):
|
|
622
692
|
"""
|
|
@@ -677,6 +747,21 @@ class SimTypePointer(SimTypeReg):
|
|
|
677
747
|
def copy(self):
|
|
678
748
|
return SimTypePointer(self.pts_to, label=self.label, offset=self.offset)
|
|
679
749
|
|
|
750
|
+
@overload
|
|
751
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
752
|
+
|
|
753
|
+
@overload
|
|
754
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
755
|
+
|
|
756
|
+
def extract(self, state, addr, concrete=False):
|
|
757
|
+
# TODO: EDG says this looks dangerously closed-minded. Just in case...
|
|
758
|
+
assert self.size % state.arch.byte_width == 0
|
|
759
|
+
|
|
760
|
+
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
761
|
+
if not concrete:
|
|
762
|
+
return out
|
|
763
|
+
return state.solver.eval(out)
|
|
764
|
+
|
|
680
765
|
|
|
681
766
|
class SimTypeReference(SimTypeReg):
|
|
682
767
|
"""
|
|
@@ -720,6 +805,21 @@ class SimTypeReference(SimTypeReg):
|
|
|
720
805
|
def copy(self):
|
|
721
806
|
return SimTypeReference(self.refs, label=self.label)
|
|
722
807
|
|
|
808
|
+
@overload
|
|
809
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
810
|
+
|
|
811
|
+
@overload
|
|
812
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
813
|
+
|
|
814
|
+
def extract(self, state, addr, concrete=False):
|
|
815
|
+
# TODO: EDG says this looks dangerously closed-minded. Just in case...
|
|
816
|
+
assert self.size % state.arch.byte_width == 0
|
|
817
|
+
|
|
818
|
+
out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
|
|
819
|
+
if not concrete:
|
|
820
|
+
return out
|
|
821
|
+
return state.solver.eval(out)
|
|
822
|
+
|
|
723
823
|
|
|
724
824
|
class SimTypeArray(SimType):
|
|
725
825
|
"""
|
|
@@ -752,6 +852,8 @@ class SimTypeArray(SimType):
|
|
|
752
852
|
def size(self):
|
|
753
853
|
if self.length is None:
|
|
754
854
|
return 0
|
|
855
|
+
if self.elem_type.size is None:
|
|
856
|
+
return None
|
|
755
857
|
return self.elem_type.size * self.length
|
|
756
858
|
|
|
757
859
|
@property
|
|
@@ -773,14 +875,27 @@ class SimTypeArray(SimType):
|
|
|
773
875
|
addr=view._addr + k * (self.elem_type.size // view.state.arch.byte_width), ty=self.elem_type
|
|
774
876
|
)
|
|
775
877
|
|
|
878
|
+
@overload
|
|
879
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> list[Any]: # associated types...
|
|
880
|
+
...
|
|
881
|
+
|
|
882
|
+
@overload
|
|
883
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> list[Any]: ...
|
|
884
|
+
|
|
776
885
|
def extract(self, state, addr, concrete=False):
|
|
886
|
+
if self.length is None:
|
|
887
|
+
return []
|
|
888
|
+
if self.elem_type.size is None:
|
|
889
|
+
return None
|
|
777
890
|
return [
|
|
778
891
|
self.elem_type.extract(state, addr + i * (self.elem_type.size // state.arch.byte_width), concrete)
|
|
779
892
|
for i in range(self.length)
|
|
780
893
|
]
|
|
781
894
|
|
|
782
|
-
def store(self, state, addr,
|
|
783
|
-
|
|
895
|
+
def store(self, state, addr, value: list[StoreType]):
|
|
896
|
+
if self.elem_type.size is None:
|
|
897
|
+
raise AngrTypeError("Cannot call store on an array of unsized types")
|
|
898
|
+
for i, val in enumerate(value):
|
|
784
899
|
self.elem_type.store(state, addr + i * (self.elem_type.size // state.arch.byte_width), val)
|
|
785
900
|
|
|
786
901
|
def _init_str(self):
|
|
@@ -795,7 +910,7 @@ class SimTypeArray(SimType):
|
|
|
795
910
|
SimTypeFixedSizeArray = SimTypeArray
|
|
796
911
|
|
|
797
912
|
|
|
798
|
-
class SimTypeString(NamedTypeMixin,
|
|
913
|
+
class SimTypeString(NamedTypeMixin, SimType):
|
|
799
914
|
"""
|
|
800
915
|
SimTypeString is a type that represents a C-style string,
|
|
801
916
|
i.e. a NUL-terminated array of bytes.
|
|
@@ -803,16 +918,31 @@ class SimTypeString(NamedTypeMixin, SimTypeArray):
|
|
|
803
918
|
|
|
804
919
|
_fields = SimTypeArray._fields + ("length",)
|
|
805
920
|
|
|
806
|
-
def __init__(self, length=None, label=None, name: str | None = None):
|
|
921
|
+
def __init__(self, length: int | None = None, label=None, name: str | None = None):
|
|
807
922
|
"""
|
|
808
923
|
:param label: The type label.
|
|
809
924
|
:param length: An expression of the length of the string, if known.
|
|
810
925
|
"""
|
|
811
|
-
super().__init__(
|
|
926
|
+
super().__init__(label=label, name=name)
|
|
927
|
+
self.elem_type = SimTypeChar()
|
|
928
|
+
self.length = length
|
|
812
929
|
|
|
813
930
|
def __repr__(self):
|
|
814
931
|
return "string_t"
|
|
815
932
|
|
|
933
|
+
def c_repr(self, name=None, full=0, memo=None, indent=0):
|
|
934
|
+
if name is None:
|
|
935
|
+
return repr(self)
|
|
936
|
+
|
|
937
|
+
name = "{}[{}]".format(name, self.length if self.length is not None else "")
|
|
938
|
+
return self.elem_type.c_repr(name, full, memo, indent)
|
|
939
|
+
|
|
940
|
+
@overload
|
|
941
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
942
|
+
|
|
943
|
+
@overload
|
|
944
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> bytes: ...
|
|
945
|
+
|
|
816
946
|
def extract(self, state: SimState, addr, concrete=False):
|
|
817
947
|
if self.length is None:
|
|
818
948
|
out = None
|
|
@@ -853,20 +983,37 @@ class SimTypeString(NamedTypeMixin, SimTypeArray):
|
|
|
853
983
|
def copy(self):
|
|
854
984
|
return SimTypeString(length=self.length, label=self.label, name=self.name)
|
|
855
985
|
|
|
986
|
+
def _init_str(self):
|
|
987
|
+
return "{}({}, {}{})".format(
|
|
988
|
+
self.__class__.__name__,
|
|
989
|
+
self.elem_type._init_str(),
|
|
990
|
+
self.length,
|
|
991
|
+
f", {self.label}" if self.label is not None else "",
|
|
992
|
+
)
|
|
993
|
+
|
|
856
994
|
|
|
857
|
-
class SimTypeWString(NamedTypeMixin,
|
|
995
|
+
class SimTypeWString(NamedTypeMixin, SimType):
|
|
858
996
|
"""
|
|
859
997
|
A wide-character null-terminated string, where each character is 2 bytes.
|
|
860
998
|
"""
|
|
861
999
|
|
|
862
1000
|
_fields = SimTypeArray._fields + ("length",)
|
|
863
1001
|
|
|
864
|
-
def __init__(self, length=None, label=None, name: str | None = None):
|
|
865
|
-
super().__init__(
|
|
1002
|
+
def __init__(self, length: int | None = None, label=None, name: str | None = None):
|
|
1003
|
+
super().__init__(label=label, name=name)
|
|
1004
|
+
self.elem_type = SimTypeNum(16, False)
|
|
1005
|
+
self.length = length
|
|
866
1006
|
|
|
867
1007
|
def __repr__(self):
|
|
868
1008
|
return "wstring_t"
|
|
869
1009
|
|
|
1010
|
+
def c_repr(self, name=None, full=0, memo=None, indent=0):
|
|
1011
|
+
if name is None:
|
|
1012
|
+
return repr(self)
|
|
1013
|
+
|
|
1014
|
+
name = "{}[{}]".format(name, self.length if self.length is not None else "")
|
|
1015
|
+
return self.elem_type.c_repr(name, full, memo, indent)
|
|
1016
|
+
|
|
870
1017
|
def extract(self, state, addr, concrete=False):
|
|
871
1018
|
if self.length is None:
|
|
872
1019
|
out = None
|
|
@@ -891,6 +1038,9 @@ class SimTypeWString(NamedTypeMixin, SimTypeArray):
|
|
|
891
1038
|
for x in out.chop(16)
|
|
892
1039
|
)
|
|
893
1040
|
|
|
1041
|
+
def store(self, state, addr, value):
|
|
1042
|
+
raise NotImplementedError
|
|
1043
|
+
|
|
894
1044
|
_can_refine_int = True
|
|
895
1045
|
|
|
896
1046
|
def _refine(self, view, k):
|
|
@@ -912,6 +1062,14 @@ class SimTypeWString(NamedTypeMixin, SimTypeArray):
|
|
|
912
1062
|
def copy(self):
|
|
913
1063
|
return SimTypeWString(length=self.length, label=self.label, name=self.name)
|
|
914
1064
|
|
|
1065
|
+
def _init_str(self):
|
|
1066
|
+
return "{}({}, {}{})".format(
|
|
1067
|
+
self.__class__.__name__,
|
|
1068
|
+
self.elem_type._init_str(),
|
|
1069
|
+
self.length,
|
|
1070
|
+
f", {self.label}" if self.label is not None else "",
|
|
1071
|
+
)
|
|
1072
|
+
|
|
915
1073
|
|
|
916
1074
|
class SimTypeFunction(SimType):
|
|
917
1075
|
"""
|
|
@@ -922,7 +1080,14 @@ class SimTypeFunction(SimType):
|
|
|
922
1080
|
_fields = ("args", "returnty")
|
|
923
1081
|
base = False
|
|
924
1082
|
|
|
925
|
-
def __init__(
|
|
1083
|
+
def __init__(
|
|
1084
|
+
self,
|
|
1085
|
+
args: Iterable[SimType],
|
|
1086
|
+
returnty: SimType | None,
|
|
1087
|
+
label=None,
|
|
1088
|
+
arg_names: Iterable[str] | None = None,
|
|
1089
|
+
variadic=False,
|
|
1090
|
+
):
|
|
926
1091
|
"""
|
|
927
1092
|
:param label: The type label
|
|
928
1093
|
:param args: A tuple of types representing the arguments to the function
|
|
@@ -930,9 +1095,9 @@ class SimTypeFunction(SimType):
|
|
|
930
1095
|
:param variadic: Whether the function accepts varargs
|
|
931
1096
|
"""
|
|
932
1097
|
super().__init__(label=label)
|
|
933
|
-
self.args:
|
|
1098
|
+
self.args: tuple[SimType, ...] = tuple(args)
|
|
934
1099
|
self.returnty: SimType | None = returnty
|
|
935
|
-
self.arg_names = arg_names if arg_names else ()
|
|
1100
|
+
self.arg_names = tuple(arg_names) if arg_names else ()
|
|
936
1101
|
self.variadic = variadic
|
|
937
1102
|
|
|
938
1103
|
def __hash__(self):
|
|
@@ -983,7 +1148,7 @@ class SimTypeFunction(SimType):
|
|
|
983
1148
|
return "{}([{}], {}{}{}{})".format(
|
|
984
1149
|
self.__class__.__name__,
|
|
985
1150
|
", ".join([arg._init_str() for arg in self.args]),
|
|
986
|
-
self.returnty._init_str(),
|
|
1151
|
+
self.returnty._init_str() if self.returnty else "void",
|
|
987
1152
|
(', label="%s"' % self.label) if self.label else "",
|
|
988
1153
|
(", arg_names=[%s]" % self._arg_names_str(show_variadic=False)) if self.arg_names else "",
|
|
989
1154
|
", variadic=True" if self.variadic else "",
|
|
@@ -1005,7 +1170,13 @@ class SimTypeCppFunction(SimTypeFunction):
|
|
|
1005
1170
|
"""
|
|
1006
1171
|
|
|
1007
1172
|
def __init__(
|
|
1008
|
-
self,
|
|
1173
|
+
self,
|
|
1174
|
+
args,
|
|
1175
|
+
returnty,
|
|
1176
|
+
label=None,
|
|
1177
|
+
arg_names: Iterable[str] | None = None,
|
|
1178
|
+
ctor: bool = False,
|
|
1179
|
+
dtor: bool = False,
|
|
1009
1180
|
):
|
|
1010
1181
|
super().__init__(args, returnty, label=label, arg_names=arg_names, variadic=False)
|
|
1011
1182
|
self.ctor = ctor
|
|
@@ -1087,18 +1258,24 @@ class SimTypeFloat(SimTypeReg):
|
|
|
1087
1258
|
sort = claripy.FSORT_FLOAT
|
|
1088
1259
|
signed = True
|
|
1089
1260
|
|
|
1261
|
+
@property
|
|
1262
|
+
def size(self) -> int:
|
|
1263
|
+
return 32
|
|
1264
|
+
|
|
1090
1265
|
def extract(self, state, addr, concrete=False):
|
|
1091
|
-
itype = claripy.fpToFP(
|
|
1266
|
+
itype = claripy.fpToFP(
|
|
1267
|
+
state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness), self.sort
|
|
1268
|
+
)
|
|
1092
1269
|
if concrete:
|
|
1093
1270
|
return state.solver.eval(itype)
|
|
1094
1271
|
return itype
|
|
1095
1272
|
|
|
1096
|
-
def store(self, state, addr, value):
|
|
1097
|
-
if
|
|
1273
|
+
def store(self, state, addr, value: StoreType | claripy.ast.FP):
|
|
1274
|
+
if isinstance(value, (int, float)):
|
|
1098
1275
|
value = claripy.FPV(float(value), self.sort)
|
|
1099
|
-
return super().store(state, addr, value)
|
|
1276
|
+
return super().store(state, addr, value) # type: ignore # trust me bro
|
|
1100
1277
|
|
|
1101
|
-
def __repr__(self):
|
|
1278
|
+
def __repr__(self) -> str:
|
|
1102
1279
|
return "float"
|
|
1103
1280
|
|
|
1104
1281
|
def _init_str(self):
|
|
@@ -1121,6 +1298,10 @@ class SimTypeDouble(SimTypeFloat):
|
|
|
1121
1298
|
|
|
1122
1299
|
sort = claripy.FSORT_DOUBLE
|
|
1123
1300
|
|
|
1301
|
+
@property
|
|
1302
|
+
def size(self) -> int:
|
|
1303
|
+
return 64
|
|
1304
|
+
|
|
1124
1305
|
def __repr__(self):
|
|
1125
1306
|
return "double"
|
|
1126
1307
|
|
|
@@ -1138,12 +1319,12 @@ class SimTypeDouble(SimTypeFloat):
|
|
|
1138
1319
|
class SimStruct(NamedTypeMixin, SimType):
|
|
1139
1320
|
_fields = ("name", "fields")
|
|
1140
1321
|
|
|
1141
|
-
def __init__(self, fields: dict[str, SimType] | OrderedDict, name=None, pack=False, align=None):
|
|
1322
|
+
def __init__(self, fields: dict[str, SimType] | OrderedDict[str, SimType], name=None, pack=False, align=None):
|
|
1142
1323
|
super().__init__(None, name="<anon>" if name is None else name)
|
|
1143
1324
|
|
|
1144
1325
|
self._pack = pack
|
|
1145
1326
|
self._align = align
|
|
1146
|
-
self.fields = fields
|
|
1327
|
+
self.fields: OrderedDict[str, SimType] = OrderedDict(fields)
|
|
1147
1328
|
|
|
1148
1329
|
self._arch_memo = {}
|
|
1149
1330
|
|
|
@@ -1153,10 +1334,13 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1153
1334
|
|
|
1154
1335
|
@property
|
|
1155
1336
|
def offsets(self) -> dict[str, int]:
|
|
1337
|
+
if self._arch is None:
|
|
1338
|
+
raise ValueError("Need an arch to calculate offsets")
|
|
1339
|
+
|
|
1156
1340
|
offsets = {}
|
|
1157
1341
|
offset_so_far = 0
|
|
1158
1342
|
for name, ty in self.fields.items():
|
|
1159
|
-
if
|
|
1343
|
+
if ty.size is None:
|
|
1160
1344
|
l.warning(
|
|
1161
1345
|
"Found a bottom field in struct %s. Ignore and increment the offset using the default "
|
|
1162
1346
|
"element size.",
|
|
@@ -1178,7 +1362,7 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1178
1362
|
|
|
1179
1363
|
return offsets
|
|
1180
1364
|
|
|
1181
|
-
def extract(self, state, addr, concrete=False):
|
|
1365
|
+
def extract(self, state, addr, concrete=False) -> SimStructValue:
|
|
1182
1366
|
values = {}
|
|
1183
1367
|
for name, offset in self.offsets.items():
|
|
1184
1368
|
ty = self.fields[name]
|
|
@@ -1194,7 +1378,7 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1194
1378
|
if arch.name in self._arch_memo:
|
|
1195
1379
|
return self._arch_memo[arch.name]
|
|
1196
1380
|
|
|
1197
|
-
out = SimStruct(
|
|
1381
|
+
out = SimStruct({}, name=self.name, pack=self._pack, align=self._align)
|
|
1198
1382
|
out._arch = arch
|
|
1199
1383
|
self._arch_memo[arch.name] = out
|
|
1200
1384
|
|
|
@@ -1202,7 +1386,7 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1202
1386
|
|
|
1203
1387
|
# Fixup the offsets to byte aligned addresses for all SimTypeNumOffset types
|
|
1204
1388
|
offset_so_far = 0
|
|
1205
|
-
for
|
|
1389
|
+
for _, ty in out.fields.items():
|
|
1206
1390
|
if isinstance(ty, SimTypeNumOffset):
|
|
1207
1391
|
out._pack = True
|
|
1208
1392
|
ty.offset = offset_so_far % arch.byte_width
|
|
@@ -1218,15 +1402,13 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1218
1402
|
|
|
1219
1403
|
indented = " " * indent if indent is not None else ""
|
|
1220
1404
|
new_indent = indent + 4 if indent is not None else None
|
|
1221
|
-
new_indented = " " * new_indent if
|
|
1405
|
+
new_indented = " " * new_indent if new_indent is not None else ""
|
|
1222
1406
|
newline = "\n" if indent is not None else " "
|
|
1223
1407
|
new_memo = (self,) + (memo if memo is not None else ())
|
|
1224
1408
|
members = newline.join(
|
|
1225
1409
|
new_indented + v.c_repr(k, full - 1, new_memo, new_indent) + ";" for k, v in self.fields.items()
|
|
1226
1410
|
)
|
|
1227
|
-
return "struct {} {{{}{}{}{}}}{}"
|
|
1228
|
-
self.name, newline, members, newline, indented, "" if name is None else " " + name
|
|
1229
|
-
)
|
|
1411
|
+
return f"struct {self.name} {{{newline}{members}{newline}{indented}}}{'' if name is None else ' ' + name}"
|
|
1230
1412
|
|
|
1231
1413
|
def __hash__(self):
|
|
1232
1414
|
return hash((SimStruct, self._name, self._align, self._pack, tuple(self.fields.keys())))
|
|
@@ -1235,11 +1417,15 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1235
1417
|
def size(self):
|
|
1236
1418
|
if not self.offsets:
|
|
1237
1419
|
return 0
|
|
1420
|
+
if self._arch is None:
|
|
1421
|
+
raise ValueError("Need an arch to compute size")
|
|
1238
1422
|
|
|
1239
1423
|
last_name, last_off = list(self.offsets.items())[-1]
|
|
1240
1424
|
last_type = self.fields[last_name]
|
|
1241
1425
|
if isinstance(last_type, SimTypeNumOffset):
|
|
1242
1426
|
return last_off * self._arch.byte_width + (last_type.size + last_type.offset)
|
|
1427
|
+
elif last_type.size is None:
|
|
1428
|
+
raise AngrTypeError("Cannot compute the size of a struct with elements with no size")
|
|
1243
1429
|
else:
|
|
1244
1430
|
return last_off * self._arch.byte_width + last_type.size
|
|
1245
1431
|
|
|
@@ -1259,7 +1445,7 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1259
1445
|
ty = self.fields[k]
|
|
1260
1446
|
return view._deeper(ty=ty, addr=view._addr + offset)
|
|
1261
1447
|
|
|
1262
|
-
def store(self, state, addr, value):
|
|
1448
|
+
def store(self, state, addr, value: StoreType):
|
|
1263
1449
|
if type(value) is dict:
|
|
1264
1450
|
pass
|
|
1265
1451
|
elif type(value) is SimStructValue:
|
|
@@ -1368,10 +1554,10 @@ class SimStructValue:
|
|
|
1368
1554
|
for f in self._struct.fields:
|
|
1369
1555
|
if isinstance(f, NamedTypeMixin) and f.name is None:
|
|
1370
1556
|
try:
|
|
1371
|
-
return f[k]
|
|
1557
|
+
return f[k] # type: ignore # lukas WHAT
|
|
1372
1558
|
except KeyError:
|
|
1373
1559
|
continue
|
|
1374
|
-
|
|
1560
|
+
raise KeyError(k)
|
|
1375
1561
|
|
|
1376
1562
|
return self._values[k]
|
|
1377
1563
|
|
|
@@ -1431,15 +1617,13 @@ class SimUnion(NamedTypeMixin, SimType):
|
|
|
1431
1617
|
|
|
1432
1618
|
indented = " " * indent if indent is not None else ""
|
|
1433
1619
|
new_indent = indent + 4 if indent is not None else None
|
|
1434
|
-
new_indented = " " * new_indent if
|
|
1620
|
+
new_indented = " " * new_indent if new_indent is not None else ""
|
|
1435
1621
|
newline = "\n" if indent is not None else " "
|
|
1436
1622
|
new_memo = (self,) + (memo if memo is not None else ())
|
|
1437
1623
|
members = newline.join(
|
|
1438
1624
|
new_indented + v.c_repr(k, full - 1, new_memo, new_indent) + ";" for k, v in self.members.items()
|
|
1439
1625
|
)
|
|
1440
|
-
return "union {} {{{}{}{}{}}}{}"
|
|
1441
|
-
self.name, newline, members, newline, indented, "" if name is None else " " + name
|
|
1442
|
-
)
|
|
1626
|
+
return f"union {self.name} {{{newline}{members}{newline}{indented}}}{'' if name is None else ' ' + name}"
|
|
1443
1627
|
|
|
1444
1628
|
def _init_str(self):
|
|
1445
1629
|
return '{}({{{}}}, name="{}", label="{}")'.format(
|
|
@@ -1498,7 +1682,7 @@ class SimUnionValue:
|
|
|
1498
1682
|
|
|
1499
1683
|
def __getitem__(self, k):
|
|
1500
1684
|
if k not in self._values:
|
|
1501
|
-
|
|
1685
|
+
raise KeyError(k)
|
|
1502
1686
|
return self._values[k]
|
|
1503
1687
|
|
|
1504
1688
|
def copy(self):
|
|
@@ -1515,7 +1699,7 @@ class SimCppClass(SimStruct):
|
|
|
1515
1699
|
pack: bool = False,
|
|
1516
1700
|
align=None,
|
|
1517
1701
|
):
|
|
1518
|
-
super().__init__(members, name=name, pack=pack, align=align)
|
|
1702
|
+
super().__init__(members or {}, name=name, pack=pack, align=align)
|
|
1519
1703
|
# these are actually addresses in the binary
|
|
1520
1704
|
self.function_members = function_members
|
|
1521
1705
|
# this should also be added to the fields once we know the offsets of the members of this object
|
|
@@ -1528,7 +1712,7 @@ class SimCppClass(SimStruct):
|
|
|
1528
1712
|
def __repr__(self):
|
|
1529
1713
|
return "class %s" % self.name
|
|
1530
1714
|
|
|
1531
|
-
def extract(self, state, addr, concrete=False):
|
|
1715
|
+
def extract(self, state, addr, concrete=False) -> SimCppClassValue:
|
|
1532
1716
|
values = {}
|
|
1533
1717
|
for name, offset in self.offsets.items():
|
|
1534
1718
|
ty = self.fields[name]
|
|
@@ -1540,7 +1724,7 @@ class SimCppClass(SimStruct):
|
|
|
1540
1724
|
|
|
1541
1725
|
return SimCppClassValue(self, values=values)
|
|
1542
1726
|
|
|
1543
|
-
def store(self, state, addr, value):
|
|
1727
|
+
def store(self, state, addr, value: StoreType):
|
|
1544
1728
|
if type(value) is dict:
|
|
1545
1729
|
pass
|
|
1546
1730
|
elif type(value) is SimCppClassValue:
|
|
@@ -1566,14 +1750,14 @@ class SimCppClass(SimStruct):
|
|
|
1566
1750
|
)
|
|
1567
1751
|
|
|
1568
1752
|
|
|
1569
|
-
class SimCppClassValue:
|
|
1753
|
+
class SimCppClassValue(SimStructValue):
|
|
1570
1754
|
"""
|
|
1571
1755
|
A SimCppClass type paired with some real values
|
|
1572
1756
|
"""
|
|
1573
1757
|
|
|
1574
|
-
def __init__(self, class_type, values):
|
|
1758
|
+
def __init__(self, class_type: SimCppClass, values):
|
|
1759
|
+
super().__init__(class_type, values)
|
|
1575
1760
|
self._class = class_type
|
|
1576
|
-
self._values = defaultdict(lambda: None, values or ())
|
|
1577
1761
|
|
|
1578
1762
|
def __indented_repr__(self, indent=0):
|
|
1579
1763
|
fields = []
|
|
@@ -1594,18 +1778,17 @@ class SimCppClassValue:
|
|
|
1594
1778
|
def __getattr__(self, k):
|
|
1595
1779
|
return self[k]
|
|
1596
1780
|
|
|
1597
|
-
def __getitem__(self, k):
|
|
1598
|
-
if
|
|
1599
|
-
k = self._class.fields[k]
|
|
1781
|
+
def __getitem__(self, k: int | str):
|
|
1782
|
+
if isinstance(k, int):
|
|
1783
|
+
k = list(self._class.fields.keys())[k]
|
|
1600
1784
|
if k not in self._values:
|
|
1601
1785
|
for f in self._class.fields:
|
|
1602
1786
|
if isinstance(f, NamedTypeMixin) and f.name is None:
|
|
1603
1787
|
try:
|
|
1604
|
-
return f[k]
|
|
1788
|
+
return f[k] # type: ignore # lukas WHAT
|
|
1605
1789
|
except KeyError:
|
|
1606
1790
|
continue
|
|
1607
|
-
|
|
1608
|
-
return self._values[k]
|
|
1791
|
+
return self._values[k]
|
|
1609
1792
|
|
|
1610
1793
|
return self._values[k]
|
|
1611
1794
|
|
|
@@ -1624,6 +1807,12 @@ class SimTypeNumOffset(SimTypeNum):
|
|
|
1624
1807
|
super().__init__(size, signed, label)
|
|
1625
1808
|
self.offset = offset
|
|
1626
1809
|
|
|
1810
|
+
@overload
|
|
1811
|
+
def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
|
|
1812
|
+
|
|
1813
|
+
@overload
|
|
1814
|
+
def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
|
|
1815
|
+
|
|
1627
1816
|
def extract(self, state: SimState, addr, concrete=False):
|
|
1628
1817
|
if state.arch.memory_endness != Endness.LE:
|
|
1629
1818
|
raise NotImplementedError("This has only been implemented and tested with Little Endian arches so far")
|
|
@@ -1659,7 +1848,7 @@ class SimTypeRef(SimType):
|
|
|
1659
1848
|
self.original_type = original_type
|
|
1660
1849
|
|
|
1661
1850
|
@property
|
|
1662
|
-
def name(self) -> str:
|
|
1851
|
+
def name(self) -> str | None:
|
|
1663
1852
|
return self.label
|
|
1664
1853
|
|
|
1665
1854
|
def set_size(self, v: int):
|
|
@@ -1678,8 +1867,8 @@ class SimTypeRef(SimType):
|
|
|
1678
1867
|
return f'SimTypeRef("{self.name}", {original_type_name})'
|
|
1679
1868
|
|
|
1680
1869
|
|
|
1681
|
-
ALL_TYPES = {}
|
|
1682
|
-
BASIC_TYPES = {
|
|
1870
|
+
ALL_TYPES: dict[str, SimType] = {}
|
|
1871
|
+
BASIC_TYPES: dict[str, SimType] = {
|
|
1683
1872
|
"char": SimTypeChar(),
|
|
1684
1873
|
"signed char": SimTypeChar(),
|
|
1685
1874
|
"unsigned char": SimTypeChar(signed=False),
|
|
@@ -2756,6 +2945,8 @@ def define_struct(defn):
|
|
|
2756
2945
|
>>> define_struct('struct abcd {int x; int y;}')
|
|
2757
2946
|
"""
|
|
2758
2947
|
struct = parse_type(defn)
|
|
2948
|
+
if not isinstance(struct, SimStruct):
|
|
2949
|
+
raise AngrTypeError("Passed a non-struct type to define_struct")
|
|
2759
2950
|
ALL_TYPES[struct.name] = struct
|
|
2760
2951
|
ALL_TYPES["struct " + struct.name] = struct
|
|
2761
2952
|
return struct
|
|
@@ -2840,6 +3031,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
2840
3031
|
if preprocess:
|
|
2841
3032
|
defn = do_preprocess(defn)
|
|
2842
3033
|
|
|
3034
|
+
# pylint: disable=unexpected-keyword-arg
|
|
2843
3035
|
node = pycparser.c_parser.CParser().parse(defn, scope_stack=_make_scope(predefined_types))
|
|
2844
3036
|
if not isinstance(node, pycparser.c_ast.FileAST):
|
|
2845
3037
|
raise ValueError("Something went horribly wrong using pycparser")
|
|
@@ -2859,12 +3051,14 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
2859
3051
|
out[piece.name] = ty
|
|
2860
3052
|
|
|
2861
3053
|
# Don't forget to update typedef types
|
|
2862
|
-
if
|
|
3054
|
+
if isinstance(ty, (SimStruct, SimUnion)) and ty.name != "<anon>":
|
|
2863
3055
|
for _, i in extra_types.items():
|
|
2864
|
-
if
|
|
3056
|
+
if isinstance(i, type(ty)) and i.name == ty.name:
|
|
2865
3057
|
if isinstance(ty, SimStruct):
|
|
3058
|
+
assert isinstance(i, SimStruct)
|
|
2866
3059
|
i.fields = ty.fields
|
|
2867
3060
|
else:
|
|
3061
|
+
assert isinstance(i, SimUnion)
|
|
2868
3062
|
i.members = ty.members
|
|
2869
3063
|
|
|
2870
3064
|
elif isinstance(piece, pycparser.c_ast.Typedef):
|
|
@@ -2877,7 +3071,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
2877
3071
|
_type_parser_singleton = None
|
|
2878
3072
|
|
|
2879
3073
|
|
|
2880
|
-
def type_parser_singleton() -> pycparser.CParser
|
|
3074
|
+
def type_parser_singleton() -> pycparser.CParser:
|
|
2881
3075
|
global _type_parser_singleton # pylint:disable=global-statement
|
|
2882
3076
|
if pycparser is not None:
|
|
2883
3077
|
if _type_parser_singleton is None:
|
|
@@ -2916,6 +3110,7 @@ def parse_type_with_name(
|
|
|
2916
3110
|
if preprocess:
|
|
2917
3111
|
defn = re.sub(r"/\*.*?\*/", r"", defn)
|
|
2918
3112
|
|
|
3113
|
+
# pylint: disable=unexpected-keyword-arg
|
|
2919
3114
|
node = type_parser_singleton().parse(text=defn, scope_stack=_make_scope(predefined_types))
|
|
2920
3115
|
if not isinstance(node, pycparser.c_ast.Typename) and not isinstance(node, pycparser.c_ast.Decl):
|
|
2921
3116
|
raise pycparser.c_parser.ParseError("Got an unexpected type out of pycparser")
|
|
@@ -2940,7 +3135,9 @@ def _accepts_scope_stack():
|
|
|
2940
3135
|
setattr(pycparser.CParser, "parse", parse)
|
|
2941
3136
|
|
|
2942
3137
|
|
|
2943
|
-
def _decl_to_type(
|
|
3138
|
+
def _decl_to_type(
|
|
3139
|
+
decl, extra_types: dict[str, SimType] | None = None, bitsize=None, arch: Arch | None = None
|
|
3140
|
+
) -> SimType:
|
|
2944
3141
|
if extra_types is None:
|
|
2945
3142
|
extra_types = {}
|
|
2946
3143
|
|
|
@@ -2967,7 +3164,12 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
|
|
|
2967
3164
|
else None
|
|
2968
3165
|
)
|
|
2969
3166
|
# special handling: func(void) is func()
|
|
2970
|
-
if
|
|
3167
|
+
if (
|
|
3168
|
+
len(argtyps) == 1
|
|
3169
|
+
and isinstance(argtyps[0], SimTypeBottom)
|
|
3170
|
+
and arg_names is not None
|
|
3171
|
+
and arg_names[0] is None
|
|
3172
|
+
):
|
|
2971
3173
|
argtyps = ()
|
|
2972
3174
|
arg_names = None
|
|
2973
3175
|
if argtyps and argtyps[-1] is ...:
|
|
@@ -2976,7 +3178,10 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
|
|
|
2976
3178
|
else:
|
|
2977
3179
|
variadic = False
|
|
2978
3180
|
r = SimTypeFunction(
|
|
2979
|
-
|
|
3181
|
+
cast(list[SimType], argtyps),
|
|
3182
|
+
_decl_to_type(decl.type, extra_types, arch=arch),
|
|
3183
|
+
arg_names=arg_names,
|
|
3184
|
+
variadic=variadic,
|
|
2980
3185
|
)
|
|
2981
3186
|
r._arch = arch
|
|
2982
3187
|
return r
|
|
@@ -3025,9 +3230,11 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
|
|
|
3025
3230
|
from_global = False
|
|
3026
3231
|
if struct is None:
|
|
3027
3232
|
struct = ALL_TYPES.get(key, None)
|
|
3028
|
-
from_global = True
|
|
3029
3233
|
if struct is not None:
|
|
3234
|
+
from_global = True
|
|
3030
3235
|
struct = struct.with_arch(arch)
|
|
3236
|
+
if struct is not None and not isinstance(struct, SimStruct):
|
|
3237
|
+
raise AngrTypeError("Provided a non-SimStruct value for a type that must be a struct")
|
|
3031
3238
|
|
|
3032
3239
|
if struct is None:
|
|
3033
3240
|
struct = SimStruct(fields, decl.name)
|
|
@@ -3055,12 +3262,14 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
|
|
|
3055
3262
|
|
|
3056
3263
|
if decl.name is not None:
|
|
3057
3264
|
key = "union " + decl.name
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3265
|
+
union = extra_types.get(key, None)
|
|
3266
|
+
from_global = False
|
|
3267
|
+
if union is None:
|
|
3268
|
+
if key in ALL_TYPES:
|
|
3269
|
+
union = ALL_TYPES[key]
|
|
3270
|
+
from_global = True
|
|
3271
|
+
if union is not None and not isinstance(union, SimUnion):
|
|
3272
|
+
raise AngrTypeError("Provided a non-SimUnion value for a type that must be a union")
|
|
3064
3273
|
|
|
3065
3274
|
if union is None:
|
|
3066
3275
|
union = SimUnion(fields, decl.name)
|
|
@@ -3068,7 +3277,11 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
|
|
|
3068
3277
|
elif not union.members:
|
|
3069
3278
|
union.members = fields
|
|
3070
3279
|
elif fields and union.members != fields:
|
|
3071
|
-
|
|
3280
|
+
if from_global:
|
|
3281
|
+
union = SimStruct(fields, decl.name)
|
|
3282
|
+
union._arch = arch
|
|
3283
|
+
else:
|
|
3284
|
+
raise ValueError("Redefining body of " + key)
|
|
3072
3285
|
|
|
3073
3286
|
extra_types[key] = union
|
|
3074
3287
|
else:
|
|
@@ -3135,6 +3348,8 @@ def _parse_const(c, arch=None, extra_types=None):
|
|
|
3135
3348
|
|
|
3136
3349
|
|
|
3137
3350
|
def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes=True):
|
|
3351
|
+
if CppHeaderParser is None:
|
|
3352
|
+
raise ImportError("Please install CppHeaderParser to parse C++ definitions")
|
|
3138
3353
|
if isinstance(decl, CppHeaderParser.CppMethod):
|
|
3139
3354
|
the_func = decl
|
|
3140
3355
|
func_name = the_func["name"]
|
|
@@ -3154,7 +3369,7 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
|
|
|
3154
3369
|
arg_names.append(arg_name)
|
|
3155
3370
|
|
|
3156
3371
|
args = tuple(args)
|
|
3157
|
-
|
|
3372
|
+
arg_names_tuple: tuple[str, ...] = tuple(arg_names)
|
|
3158
3373
|
# returns
|
|
3159
3374
|
if not the_func["returns"].strip():
|
|
3160
3375
|
returnty = SimTypeBottom()
|
|
@@ -3163,7 +3378,7 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
|
|
|
3163
3378
|
# other properties
|
|
3164
3379
|
ctor = the_func["constructor"]
|
|
3165
3380
|
dtor = the_func["destructor"]
|
|
3166
|
-
func = SimTypeCppFunction(args, returnty, arg_names=
|
|
3381
|
+
func = SimTypeCppFunction(args, returnty, arg_names=arg_names_tuple, ctor=ctor, dtor=dtor)
|
|
3167
3382
|
return func
|
|
3168
3383
|
|
|
3169
3384
|
elif isinstance(decl, str):
|
|
@@ -3202,9 +3417,9 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
|
|
|
3202
3417
|
else:
|
|
3203
3418
|
raise TypeError("Unknown type '%s'" % " ".join(key))
|
|
3204
3419
|
|
|
3205
|
-
if unqualified_name != decl:
|
|
3420
|
+
if unqualified_name != decl and isinstance(t, NamedTypeMixin):
|
|
3206
3421
|
t = t.copy()
|
|
3207
|
-
t.name = decl
|
|
3422
|
+
t.name = decl # pylint:disable=attribute-defined-outside-init
|
|
3208
3423
|
return t
|
|
3209
3424
|
|
|
3210
3425
|
raise NotImplementedError()
|
|
@@ -3216,6 +3431,7 @@ def normalize_cpp_function_name(name: str) -> str:
|
|
|
3216
3431
|
while s != _s:
|
|
3217
3432
|
_s = s if s is not None else _s
|
|
3218
3433
|
s = re.sub(r"<[^<>]+>", "", _s)
|
|
3434
|
+
assert s is not None
|
|
3219
3435
|
|
|
3220
3436
|
m = re.search(r"{([a-z\s]+)}", s)
|
|
3221
3437
|
if m is not None:
|
|
@@ -3270,15 +3486,17 @@ def parse_cpp_file(cpp_decl, with_param_names: bool = False):
|
|
|
3270
3486
|
func_decls: dict[str, SimTypeCppFunction] = {}
|
|
3271
3487
|
for the_func in h.functions:
|
|
3272
3488
|
# FIXME: We always assume that there is a "this" pointer but it is not the case for static methods.
|
|
3273
|
-
proto
|
|
3489
|
+
proto = cast(Optional[SimTypeCppFunction], _cpp_decl_to_type(the_func, {}, opaque_classes=True))
|
|
3274
3490
|
if proto is not None and the_func["class"]:
|
|
3275
|
-
func_name = the_func["class"] + "::" + the_func["name"]
|
|
3276
|
-
proto.args = (
|
|
3277
|
-
|
|
3278
|
-
)
|
|
3491
|
+
func_name = cast(str, the_func["class"] + "::" + the_func["name"])
|
|
3492
|
+
proto.args = (SimTypePointer(pts_to=SimTypeBottom(label="void")),) + tuple(
|
|
3493
|
+
proto.args
|
|
3494
|
+
) # pylint:disable=attribute-defined-outside-init
|
|
3279
3495
|
proto.arg_names = ("this",) + proto.arg_names # pylint:disable=attribute-defined-outside-init
|
|
3496
|
+
elif proto is None:
|
|
3497
|
+
raise ValueError("proto is None but class is also None... not sure what this edge case means")
|
|
3280
3498
|
else:
|
|
3281
|
-
func_name = the_func["name"]
|
|
3499
|
+
func_name = cast(str, the_func["name"])
|
|
3282
3500
|
func_decls[func_name] = proto
|
|
3283
3501
|
|
|
3284
3502
|
return func_decls, {}
|
|
@@ -3296,7 +3514,7 @@ def dereference_simtype(
|
|
|
3296
3514
|
if t.name in memo:
|
|
3297
3515
|
return memo[t.name]
|
|
3298
3516
|
|
|
3299
|
-
if type_collections:
|
|
3517
|
+
if type_collections and t.name is not None:
|
|
3300
3518
|
for tc in type_collections:
|
|
3301
3519
|
try:
|
|
3302
3520
|
real_type = tc.get(t.name)
|
|
@@ -3334,7 +3552,7 @@ def dereference_simtype(
|
|
|
3334
3552
|
dereference_simtype(t.returnty, type_collections, memo=memo) if t.returnty is not None else None
|
|
3335
3553
|
)
|
|
3336
3554
|
real_type = t.copy()
|
|
3337
|
-
real_type.args = real_args
|
|
3555
|
+
real_type.args = tuple(real_args)
|
|
3338
3556
|
real_type.returnty = real_return_type
|
|
3339
3557
|
else:
|
|
3340
3558
|
return t
|