angr 9.2.148__py3-none-macosx_11_0_arm64.whl → 9.2.150__py3-none-macosx_11_0_arm64.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/__main__.py +100 -37
- angr/analyses/calling_convention/calling_convention.py +42 -2
- angr/analyses/cfg/cfg_emulated.py +5 -2
- angr/analyses/cfg/cfg_fast.py +48 -46
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/clinic.py +80 -13
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +141 -10
- angr/analyses/decompiler/utils.py +23 -1
- angr/analyses/disassembly.py +2 -1
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +25 -6
- angr/analyses/variable_recovery/engine_ail.py +44 -5
- angr/analyses/variable_recovery/engine_base.py +35 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +23 -5
- angr/engines/light/engine.py +7 -0
- angr/engines/pcode/lifter.py +7 -0
- angr/knowledge_plugins/functions/function.py +68 -0
- angr/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/lib/angr_native.dylib +0 -0
- angr/procedures/definitions/__init__.py +1 -1
- angr/procedures/definitions/types_stl.py +22 -0
- angr/sim_type.py +251 -130
- angr/utils/graph.py +51 -27
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/METADATA +7 -7
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/RECORD +62 -56
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/WHEEL +1 -1
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/licenses/LICENSE +3 -0
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/entry_points.txt +0 -0
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/top_level.txt +0 -0
angr/sim_type.py
CHANGED
|
@@ -11,8 +11,11 @@ from typing import Literal, Any, TYPE_CHECKING, cast, overload
|
|
|
11
11
|
|
|
12
12
|
from archinfo import Endness, Arch
|
|
13
13
|
import claripy
|
|
14
|
-
import
|
|
14
|
+
import cxxheaderparser.simple
|
|
15
|
+
import cxxheaderparser.errors
|
|
16
|
+
import cxxheaderparser.types
|
|
15
17
|
import pycparser
|
|
18
|
+
from pycparser import c_ast
|
|
16
19
|
|
|
17
20
|
from angr.errors import AngrMissingTypeError, AngrTypeError
|
|
18
21
|
from angr.sim_state import SimState
|
|
@@ -268,7 +271,7 @@ class SimTypeBottom(SimType):
|
|
|
268
271
|
self, name=None, full=0, memo=None, indent=0, name_parens: bool = True
|
|
269
272
|
): # pylint: disable=unused-argument
|
|
270
273
|
if name is None:
|
|
271
|
-
return "int"
|
|
274
|
+
return "int" if self.label is None else self.label
|
|
272
275
|
return f'{"int" if self.label is None else self.label} {name}'
|
|
273
276
|
|
|
274
277
|
def _init_str(self):
|
|
@@ -501,7 +504,9 @@ class SimTypeFixedSizeInt(SimTypeInt):
|
|
|
501
504
|
_base_name: str = "int"
|
|
502
505
|
_fixed_size: int = 32
|
|
503
506
|
|
|
504
|
-
def c_repr(
|
|
507
|
+
def c_repr(
|
|
508
|
+
self, name=None, full=0, memo=None, indent=0, name_parens: bool = True # pylint:disable=unused-argument
|
|
509
|
+
):
|
|
505
510
|
out = self._base_name
|
|
506
511
|
if not self.signed:
|
|
507
512
|
out = "u" + out
|
|
@@ -1215,10 +1220,12 @@ class SimTypeCppFunction(SimTypeFunction):
|
|
|
1215
1220
|
arg_names: Iterable[str] | None = None,
|
|
1216
1221
|
ctor: bool = False,
|
|
1217
1222
|
dtor: bool = False,
|
|
1223
|
+
convention: str | None = None,
|
|
1218
1224
|
):
|
|
1219
1225
|
super().__init__(args, returnty, label=label, arg_names=arg_names, variadic=False)
|
|
1220
1226
|
self.ctor = ctor
|
|
1221
1227
|
self.dtor = dtor
|
|
1228
|
+
self.convention = convention
|
|
1222
1229
|
|
|
1223
1230
|
def __repr__(self):
|
|
1224
1231
|
argstrs = [str(a) for a in self.args]
|
|
@@ -1236,6 +1243,19 @@ class SimTypeCppFunction(SimTypeFunction):
|
|
|
1236
1243
|
", variadic=True" if self.variadic else "",
|
|
1237
1244
|
)
|
|
1238
1245
|
|
|
1246
|
+
def _with_arch(self, arch):
|
|
1247
|
+
out = SimTypeCppFunction(
|
|
1248
|
+
[a.with_arch(arch) for a in self.args],
|
|
1249
|
+
self.returnty.with_arch(arch) if self.returnty is not None else None,
|
|
1250
|
+
label=self.label,
|
|
1251
|
+
arg_names=self.arg_names,
|
|
1252
|
+
ctor=self.ctor,
|
|
1253
|
+
dtor=self.dtor,
|
|
1254
|
+
convention=self.convention,
|
|
1255
|
+
)
|
|
1256
|
+
out._arch = arch
|
|
1257
|
+
return out
|
|
1258
|
+
|
|
1239
1259
|
def copy(self):
|
|
1240
1260
|
return SimTypeCppFunction(
|
|
1241
1261
|
self.args,
|
|
@@ -1244,6 +1264,7 @@ class SimTypeCppFunction(SimTypeFunction):
|
|
|
1244
1264
|
arg_names=self.arg_names,
|
|
1245
1265
|
ctor=self.ctor,
|
|
1246
1266
|
dtor=self.dtor,
|
|
1267
|
+
convention=self.convention,
|
|
1247
1268
|
)
|
|
1248
1269
|
|
|
1249
1270
|
|
|
@@ -1504,6 +1525,7 @@ class SimStruct(NamedTypeMixin, SimType):
|
|
|
1504
1525
|
else:
|
|
1505
1526
|
raise TypeError(f"Can't store struct of type {type(value)}")
|
|
1506
1527
|
|
|
1528
|
+
assert isinstance(value, dict)
|
|
1507
1529
|
if len(value) != len(self.fields):
|
|
1508
1530
|
raise ValueError(f"Passed bad values for {self}; expected {len(self.offsets)}, got {len(value)}")
|
|
1509
1531
|
|
|
@@ -1749,14 +1771,17 @@ class SimUnionValue:
|
|
|
1749
1771
|
class SimCppClass(SimStruct):
|
|
1750
1772
|
def __init__(
|
|
1751
1773
|
self,
|
|
1774
|
+
*,
|
|
1775
|
+
unique_name: str | None = None,
|
|
1776
|
+
name: str | None = None,
|
|
1752
1777
|
members: dict[str, SimType] | None = None,
|
|
1753
1778
|
function_members: dict[str, SimTypeCppFunction] | None = None,
|
|
1754
1779
|
vtable_ptrs=None,
|
|
1755
|
-
name: str | None = None,
|
|
1756
1780
|
pack: bool = False,
|
|
1757
1781
|
align=None,
|
|
1758
1782
|
):
|
|
1759
1783
|
super().__init__(members or {}, name=name, pack=pack, align=align)
|
|
1784
|
+
self.unique_name = unique_name
|
|
1760
1785
|
# these are actually addresses in the binary
|
|
1761
1786
|
self.function_members = function_members
|
|
1762
1787
|
# this should also be added to the fields once we know the offsets of the members of this object
|
|
@@ -1766,8 +1791,12 @@ class SimCppClass(SimStruct):
|
|
|
1766
1791
|
def members(self):
|
|
1767
1792
|
return self.fields
|
|
1768
1793
|
|
|
1794
|
+
@members.setter
|
|
1795
|
+
def members(self, value):
|
|
1796
|
+
self.fields = value
|
|
1797
|
+
|
|
1769
1798
|
def __repr__(self):
|
|
1770
|
-
return f"class {self.name}"
|
|
1799
|
+
return f"class {self.name}" if not self.name.startswith("class") else self.name
|
|
1771
1800
|
|
|
1772
1801
|
def extract(self, state, addr, concrete=False) -> SimCppClassValue:
|
|
1773
1802
|
values = {}
|
|
@@ -1789,6 +1818,7 @@ class SimCppClass(SimStruct):
|
|
|
1789
1818
|
else:
|
|
1790
1819
|
raise TypeError(f"Can't store struct of type {type(value)}")
|
|
1791
1820
|
|
|
1821
|
+
assert isinstance(value, dict)
|
|
1792
1822
|
if len(value) != len(self.fields):
|
|
1793
1823
|
raise ValueError(f"Passed bad values for {self}; expected {len(self.offsets)}, got {len(value)}")
|
|
1794
1824
|
|
|
@@ -1796,10 +1826,43 @@ class SimCppClass(SimStruct):
|
|
|
1796
1826
|
ty = self.fields[field]
|
|
1797
1827
|
ty.store(state, addr + offset, value[field])
|
|
1798
1828
|
|
|
1829
|
+
def _with_arch(self, arch) -> SimCppClass:
|
|
1830
|
+
if arch.name in self._arch_memo:
|
|
1831
|
+
return self._arch_memo[arch.name]
|
|
1832
|
+
|
|
1833
|
+
out = SimCppClass(
|
|
1834
|
+
unique_name=self.unique_name,
|
|
1835
|
+
name=self.name,
|
|
1836
|
+
members={},
|
|
1837
|
+
function_members={},
|
|
1838
|
+
vtable_ptrs=self.vtable_ptrs,
|
|
1839
|
+
pack=self._pack,
|
|
1840
|
+
align=self._align,
|
|
1841
|
+
)
|
|
1842
|
+
out._arch = arch
|
|
1843
|
+
self._arch_memo[arch.name] = out
|
|
1844
|
+
|
|
1845
|
+
out.members = OrderedDict((k, v.with_arch(arch)) for k, v in self.members.items())
|
|
1846
|
+
out.function_members = (
|
|
1847
|
+
OrderedDict((k, v.with_arch(arch)) for k, v in self.function_members.items())
|
|
1848
|
+
if self.function_members is not None
|
|
1849
|
+
else None
|
|
1850
|
+
)
|
|
1851
|
+
|
|
1852
|
+
# Fixup the offsets to byte aligned addresses for all SimTypeNumOffset types
|
|
1853
|
+
offset_so_far = 0
|
|
1854
|
+
for _, ty in out.members.items():
|
|
1855
|
+
if isinstance(ty, SimTypeNumOffset):
|
|
1856
|
+
out._pack = True
|
|
1857
|
+
ty.offset = offset_so_far % arch.byte_width
|
|
1858
|
+
offset_so_far += ty.size
|
|
1859
|
+
return out
|
|
1860
|
+
|
|
1799
1861
|
def copy(self):
|
|
1800
1862
|
return SimCppClass(
|
|
1801
|
-
|
|
1863
|
+
unique_name=self.unique_name,
|
|
1802
1864
|
name=self.name,
|
|
1865
|
+
members=dict(self.fields),
|
|
1803
1866
|
pack=self._pack,
|
|
1804
1867
|
align=self._align,
|
|
1805
1868
|
function_members=self.function_members,
|
|
@@ -2041,10 +2104,11 @@ GLIBC_EXTERNAL_BASIC_TYPES = {
|
|
|
2041
2104
|
}
|
|
2042
2105
|
ALL_TYPES.update(GLIBC_EXTERNAL_BASIC_TYPES)
|
|
2043
2106
|
|
|
2044
|
-
|
|
2107
|
+
# TODO: switch to stl types declared in types_stl
|
|
2045
2108
|
CXX_TYPES = {
|
|
2046
2109
|
"string": SimTypeString(),
|
|
2047
2110
|
"wstring": SimTypeWString(),
|
|
2111
|
+
"std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>": SimTypeString(),
|
|
2048
2112
|
"basic_string": SimTypeString(),
|
|
2049
2113
|
"CharT": SimTypeChar(),
|
|
2050
2114
|
}
|
|
@@ -3077,7 +3141,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
3077
3141
|
|
|
3078
3142
|
# pylint: disable=unexpected-keyword-arg
|
|
3079
3143
|
node = pycparser.c_parser.CParser().parse(defn, scope_stack=_make_scope(predefined_types))
|
|
3080
|
-
if not isinstance(node,
|
|
3144
|
+
if not isinstance(node, c_ast.FileAST):
|
|
3081
3145
|
raise ValueError("Something went horribly wrong using pycparser")
|
|
3082
3146
|
out = {}
|
|
3083
3147
|
extra_types = {}
|
|
@@ -3087,9 +3151,9 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
3087
3151
|
extra_types = dict(predefined_types)
|
|
3088
3152
|
|
|
3089
3153
|
for piece in node.ext:
|
|
3090
|
-
if isinstance(piece,
|
|
3154
|
+
if isinstance(piece, c_ast.FuncDef):
|
|
3091
3155
|
out[piece.decl.name] = _decl_to_type(piece.decl.type, extra_types, arch=arch)
|
|
3092
|
-
elif isinstance(piece,
|
|
3156
|
+
elif isinstance(piece, c_ast.Decl):
|
|
3093
3157
|
ty = _decl_to_type(piece.type, extra_types, arch=arch)
|
|
3094
3158
|
if piece.name is not None:
|
|
3095
3159
|
out[piece.name] = ty
|
|
@@ -3105,7 +3169,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
|
|
|
3105
3169
|
assert isinstance(i, SimUnion)
|
|
3106
3170
|
i.members = ty.members
|
|
3107
3171
|
|
|
3108
|
-
elif isinstance(piece,
|
|
3172
|
+
elif isinstance(piece, c_ast.Typedef):
|
|
3109
3173
|
extra_types[piece.name] = copy.copy(_decl_to_type(piece.type, extra_types, arch=arch))
|
|
3110
3174
|
extra_types[piece.name].label = piece.name
|
|
3111
3175
|
|
|
@@ -3126,6 +3190,7 @@ def type_parser_singleton() -> pycparser.CParser:
|
|
|
3126
3190
|
optimize=False,
|
|
3127
3191
|
errorlog=errorlog,
|
|
3128
3192
|
)
|
|
3193
|
+
assert _type_parser_singleton is not None
|
|
3129
3194
|
return _type_parser_singleton
|
|
3130
3195
|
|
|
3131
3196
|
|
|
@@ -3155,7 +3220,7 @@ def parse_type_with_name(
|
|
|
3155
3220
|
|
|
3156
3221
|
# pylint: disable=unexpected-keyword-arg
|
|
3157
3222
|
node = type_parser_singleton().parse(text=defn, scope_stack=_make_scope(predefined_types))
|
|
3158
|
-
if not isinstance(node,
|
|
3223
|
+
if not isinstance(node, c_ast.Typename) and not isinstance(node, c_ast.Decl):
|
|
3159
3224
|
raise pycparser.c_parser.ParseError("Got an unexpected type out of pycparser")
|
|
3160
3225
|
|
|
3161
3226
|
decl = node.type
|
|
@@ -3184,17 +3249,17 @@ def _decl_to_type(
|
|
|
3184
3249
|
if extra_types is None:
|
|
3185
3250
|
extra_types = {}
|
|
3186
3251
|
|
|
3187
|
-
if isinstance(decl,
|
|
3252
|
+
if isinstance(decl, c_ast.FuncDecl):
|
|
3188
3253
|
argtyps = (
|
|
3189
3254
|
()
|
|
3190
3255
|
if decl.args is None
|
|
3191
3256
|
else [
|
|
3192
3257
|
(
|
|
3193
3258
|
...
|
|
3194
|
-
if type(x) is
|
|
3259
|
+
if type(x) is c_ast.EllipsisParam
|
|
3195
3260
|
else (
|
|
3196
3261
|
SimTypeBottom().with_arch(arch)
|
|
3197
|
-
if type(x) is
|
|
3262
|
+
if type(x) is c_ast.ID
|
|
3198
3263
|
else _decl_to_type(x.type, extra_types, arch=arch)
|
|
3199
3264
|
)
|
|
3200
3265
|
)
|
|
@@ -3202,9 +3267,7 @@ def _decl_to_type(
|
|
|
3202
3267
|
]
|
|
3203
3268
|
)
|
|
3204
3269
|
arg_names = (
|
|
3205
|
-
[arg.name for arg in decl.args.params if type(arg) is not
|
|
3206
|
-
if decl.args
|
|
3207
|
-
else None
|
|
3270
|
+
[arg.name for arg in decl.args.params if type(arg) is not c_ast.EllipsisParam] if decl.args else None
|
|
3208
3271
|
)
|
|
3209
3272
|
# special handling: func(void) is func()
|
|
3210
3273
|
if (
|
|
@@ -3229,20 +3292,20 @@ def _decl_to_type(
|
|
|
3229
3292
|
r._arch = arch
|
|
3230
3293
|
return r
|
|
3231
3294
|
|
|
3232
|
-
if isinstance(decl,
|
|
3295
|
+
if isinstance(decl, c_ast.TypeDecl):
|
|
3233
3296
|
if decl.declname == "TOP":
|
|
3234
3297
|
r = SimTypeTop()
|
|
3235
3298
|
r._arch = arch
|
|
3236
3299
|
return r
|
|
3237
3300
|
return _decl_to_type(decl.type, extra_types, bitsize=bitsize, arch=arch)
|
|
3238
3301
|
|
|
3239
|
-
if isinstance(decl,
|
|
3302
|
+
if isinstance(decl, c_ast.PtrDecl):
|
|
3240
3303
|
pts_to = _decl_to_type(decl.type, extra_types, arch=arch)
|
|
3241
3304
|
r = SimTypePointer(pts_to)
|
|
3242
3305
|
r._arch = arch
|
|
3243
3306
|
return r
|
|
3244
3307
|
|
|
3245
|
-
if isinstance(decl,
|
|
3308
|
+
if isinstance(decl, c_ast.ArrayDecl):
|
|
3246
3309
|
elem_type = _decl_to_type(decl.type, extra_types, arch=arch)
|
|
3247
3310
|
|
|
3248
3311
|
if decl.dim is None:
|
|
@@ -3258,7 +3321,7 @@ def _decl_to_type(
|
|
|
3258
3321
|
r._arch = arch
|
|
3259
3322
|
return r
|
|
3260
3323
|
|
|
3261
|
-
if isinstance(decl,
|
|
3324
|
+
if isinstance(decl, c_ast.Struct):
|
|
3262
3325
|
if decl.decls is not None:
|
|
3263
3326
|
fields = OrderedDict(
|
|
3264
3327
|
(field.name, _decl_to_type(field.type, extra_types, bitsize=field.bitsize, arch=arch))
|
|
@@ -3297,7 +3360,7 @@ def _decl_to_type(
|
|
|
3297
3360
|
struct._arch = arch
|
|
3298
3361
|
return struct
|
|
3299
3362
|
|
|
3300
|
-
if isinstance(decl,
|
|
3363
|
+
if isinstance(decl, c_ast.Union):
|
|
3301
3364
|
if decl.decls is not None:
|
|
3302
3365
|
fields = {field.name: _decl_to_type(field.type, extra_types, arch=arch) for field in decl.decls}
|
|
3303
3366
|
else:
|
|
@@ -3331,7 +3394,7 @@ def _decl_to_type(
|
|
|
3331
3394
|
union._arch = arch
|
|
3332
3395
|
return union
|
|
3333
3396
|
|
|
3334
|
-
if isinstance(decl,
|
|
3397
|
+
if isinstance(decl, c_ast.IdentifierType):
|
|
3335
3398
|
key = " ".join(decl.names)
|
|
3336
3399
|
if bitsize is not None:
|
|
3337
3400
|
return SimTypeNumOffset(int(bitsize.value), signed=False)
|
|
@@ -3341,7 +3404,7 @@ def _decl_to_type(
|
|
|
3341
3404
|
return ALL_TYPES[key].with_arch(arch)
|
|
3342
3405
|
raise TypeError(f"Unknown type '{key}'")
|
|
3343
3406
|
|
|
3344
|
-
if isinstance(decl,
|
|
3407
|
+
if isinstance(decl, c_ast.Enum):
|
|
3345
3408
|
# See C99 at 6.7.2.2
|
|
3346
3409
|
return ALL_TYPES["int"].with_arch(arch)
|
|
3347
3410
|
|
|
@@ -3349,9 +3412,9 @@ def _decl_to_type(
|
|
|
3349
3412
|
|
|
3350
3413
|
|
|
3351
3414
|
def _parse_const(c, arch=None, extra_types=None):
|
|
3352
|
-
if type(c) is
|
|
3415
|
+
if type(c) is c_ast.Constant:
|
|
3353
3416
|
return int(c.value, base=0)
|
|
3354
|
-
if type(c) is
|
|
3417
|
+
if type(c) is c_ast.BinaryOp:
|
|
3355
3418
|
if c.op == "+":
|
|
3356
3419
|
return _parse_const(c.children()[0][1], arch, extra_types) + _parse_const(
|
|
3357
3420
|
c.children()[1][1], arch, extra_types
|
|
@@ -3377,156 +3440,214 @@ def _parse_const(c, arch=None, extra_types=None):
|
|
|
3377
3440
|
c.children()[1][1], arch, extra_types
|
|
3378
3441
|
)
|
|
3379
3442
|
raise ValueError(f"Binary op {c.op}")
|
|
3380
|
-
if type(c) is
|
|
3443
|
+
if type(c) is c_ast.UnaryOp:
|
|
3381
3444
|
if c.op == "sizeof":
|
|
3382
3445
|
return _decl_to_type(c.expr.type, extra_types=extra_types, arch=arch).size
|
|
3383
3446
|
raise ValueError(f"Unary op {c.op}")
|
|
3384
|
-
if type(c) is
|
|
3447
|
+
if type(c) is c_ast.Cast:
|
|
3385
3448
|
return _parse_const(c.expr, arch, extra_types)
|
|
3386
3449
|
raise ValueError(c)
|
|
3387
3450
|
|
|
3388
3451
|
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3452
|
+
CPP_DECL_TYPES = (
|
|
3453
|
+
cxxheaderparser.types.Method
|
|
3454
|
+
| cxxheaderparser.types.Array
|
|
3455
|
+
| cxxheaderparser.types.Pointer
|
|
3456
|
+
| cxxheaderparser.types.MoveReference
|
|
3457
|
+
| cxxheaderparser.types.Reference
|
|
3458
|
+
| cxxheaderparser.types.FunctionType
|
|
3459
|
+
| cxxheaderparser.types.Function
|
|
3460
|
+
| cxxheaderparser.types.Type
|
|
3461
|
+
)
|
|
3462
|
+
|
|
3463
|
+
|
|
3464
|
+
def _cpp_decl_to_type(
|
|
3465
|
+
decl: CPP_DECL_TYPES, extra_types: dict[str, SimType], opaque_classes: bool = True
|
|
3466
|
+
) -> (
|
|
3467
|
+
SimTypeCppFunction
|
|
3468
|
+
| SimTypeFunction
|
|
3469
|
+
| SimCppClass
|
|
3470
|
+
| SimTypeReference
|
|
3471
|
+
| SimTypePointer
|
|
3472
|
+
| SimTypeArray
|
|
3473
|
+
| SimTypeBottom
|
|
3474
|
+
):
|
|
3475
|
+
if cxxheaderparser is None:
|
|
3476
|
+
raise ImportError("Please install cxxheaderparser to parse C++ definitions")
|
|
3477
|
+
if isinstance(decl, cxxheaderparser.types.Method):
|
|
3393
3478
|
the_func = decl
|
|
3394
|
-
func_name = the_func
|
|
3395
|
-
if "__deleting_dtor__" in func_name or "__base_dtor__" in func_name or "__dtor__" in func_name:
|
|
3396
|
-
the_func["destructor"] = True
|
|
3479
|
+
func_name = the_func.name.format()
|
|
3397
3480
|
# translate parameters
|
|
3398
3481
|
args = []
|
|
3399
3482
|
arg_names: list[str] = []
|
|
3400
|
-
for param in the_func
|
|
3401
|
-
arg_type = param
|
|
3483
|
+
for idx, param in enumerate(the_func.parameters):
|
|
3484
|
+
arg_type = param.type
|
|
3402
3485
|
args.append(_cpp_decl_to_type(arg_type, extra_types, opaque_classes=opaque_classes))
|
|
3403
|
-
arg_name = param
|
|
3486
|
+
arg_name = param.name if param.name is not None else f"unknown_{idx}"
|
|
3404
3487
|
arg_names.append(arg_name)
|
|
3405
3488
|
|
|
3406
3489
|
args = tuple(args)
|
|
3407
3490
|
arg_names_tuple: tuple[str, ...] = tuple(arg_names)
|
|
3491
|
+
|
|
3492
|
+
# note that the constructor and destructor handling in cxxheaderparser is a bit weird and I could not get it to
|
|
3493
|
+
# work, hence the following hack
|
|
3494
|
+
ctor = dtor = False
|
|
3495
|
+
convention = the_func.msvc_convention
|
|
3496
|
+
if len(the_func.name.segments) >= 2:
|
|
3497
|
+
seg1, seg0 = the_func.name.segments[-2:]
|
|
3498
|
+
seg1 = seg1.format()
|
|
3499
|
+
seg0 = seg0.format()
|
|
3500
|
+
if seg0 == seg1:
|
|
3501
|
+
ctor = True
|
|
3502
|
+
if the_func.return_type is not None:
|
|
3503
|
+
convention = the_func.return_type.format() # it's usually just "__thiscall"
|
|
3504
|
+
elif seg0 == "~" + seg1:
|
|
3505
|
+
dtor = True
|
|
3506
|
+
if the_func.return_type is not None:
|
|
3507
|
+
convention = the_func.return_type.format() # it's usually just "__thiscall"
|
|
3408
3508
|
# returns
|
|
3409
|
-
if
|
|
3509
|
+
if the_func.return_type is None or ctor or dtor:
|
|
3410
3510
|
returnty = SimTypeBottom()
|
|
3411
3511
|
else:
|
|
3412
|
-
returnty = _cpp_decl_to_type(the_func
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
if
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3512
|
+
returnty = _cpp_decl_to_type(the_func.return_type, extra_types, opaque_classes=opaque_classes)
|
|
3513
|
+
return SimTypeCppFunction(
|
|
3514
|
+
args,
|
|
3515
|
+
returnty,
|
|
3516
|
+
label=func_name,
|
|
3517
|
+
arg_names=arg_names_tuple,
|
|
3518
|
+
ctor=ctor,
|
|
3519
|
+
dtor=dtor,
|
|
3520
|
+
convention=convention,
|
|
3521
|
+
)
|
|
3522
|
+
|
|
3523
|
+
if isinstance(decl, cxxheaderparser.types.Function):
|
|
3524
|
+
# a function declaration
|
|
3525
|
+
the_func = decl
|
|
3526
|
+
func_name = the_func.name.format()
|
|
3527
|
+
# translate parameters
|
|
3528
|
+
args = []
|
|
3529
|
+
arg_names: list[str] = []
|
|
3530
|
+
for idx, param in enumerate(the_func.parameters):
|
|
3531
|
+
arg_type = param.type
|
|
3532
|
+
args.append(_cpp_decl_to_type(arg_type, extra_types, opaque_classes=opaque_classes))
|
|
3533
|
+
arg_name = param.name if param.name is not None else f"unknown_{idx}"
|
|
3534
|
+
arg_names.append(arg_name)
|
|
3535
|
+
|
|
3536
|
+
args = tuple(args)
|
|
3537
|
+
arg_names_tuple: tuple[str, ...] = tuple(arg_names)
|
|
3538
|
+
# returns
|
|
3539
|
+
if the_func.return_type is None:
|
|
3540
|
+
returnty = SimTypeBottom()
|
|
3541
|
+
else:
|
|
3542
|
+
returnty = _cpp_decl_to_type(the_func.return_type, extra_types, opaque_classes=opaque_classes)
|
|
3543
|
+
|
|
3544
|
+
return SimTypeFunction(args, returnty, label=func_name, arg_names=arg_names_tuple)
|
|
3545
|
+
|
|
3546
|
+
if isinstance(decl, cxxheaderparser.types.Type):
|
|
3547
|
+
# attempt to parse it as one of the existing types
|
|
3548
|
+
lbl = decl.format()
|
|
3549
|
+
lbl = lbl.removeprefix("const ")
|
|
3550
|
+
if lbl in extra_types:
|
|
3551
|
+
t = extra_types[lbl]
|
|
3552
|
+
elif lbl in ALL_TYPES:
|
|
3553
|
+
t = ALL_TYPES[lbl]
|
|
3443
3554
|
elif opaque_classes is True:
|
|
3444
3555
|
# create a class without knowing the internal members
|
|
3445
|
-
t = SimCppClass(
|
|
3556
|
+
t = SimCppClass(unique_name=lbl, name=lbl, members={})
|
|
3446
3557
|
else:
|
|
3447
|
-
raise TypeError(
|
|
3558
|
+
raise TypeError(f'Unknown type "{lbl}"')
|
|
3448
3559
|
|
|
3449
|
-
if
|
|
3560
|
+
if isinstance(t, NamedTypeMixin):
|
|
3450
3561
|
t = t.copy()
|
|
3451
|
-
t.name =
|
|
3452
|
-
return t
|
|
3562
|
+
t.name = lbl # pylint:disable=attribute-defined-outside-init
|
|
3563
|
+
return t # type:ignore
|
|
3564
|
+
|
|
3565
|
+
if isinstance(decl, cxxheaderparser.types.Array):
|
|
3566
|
+
subt = _cpp_decl_to_type(decl.array_of, extra_types, opaque_classes=opaque_classes)
|
|
3567
|
+
return SimTypeArray(subt, length=decl.size)
|
|
3568
|
+
|
|
3569
|
+
if isinstance(decl, cxxheaderparser.types.MoveReference):
|
|
3570
|
+
subt = _cpp_decl_to_type(decl.moveref_to, extra_types, opaque_classes=opaque_classes)
|
|
3571
|
+
return SimTypeReference(subt) # FIXME: Move reference vs reference
|
|
3572
|
+
|
|
3573
|
+
if isinstance(decl, cxxheaderparser.types.Reference):
|
|
3574
|
+
subt = _cpp_decl_to_type(decl.ref_to, extra_types, opaque_classes=opaque_classes)
|
|
3575
|
+
return SimTypeReference(subt)
|
|
3576
|
+
|
|
3577
|
+
if isinstance(decl, cxxheaderparser.types.Pointer):
|
|
3578
|
+
subt = _cpp_decl_to_type(decl.ptr_to, extra_types, opaque_classes=opaque_classes)
|
|
3579
|
+
return SimTypePointer(subt)
|
|
3580
|
+
|
|
3581
|
+
if isinstance(decl, cxxheaderparser.types.FunctionType):
|
|
3582
|
+
params = tuple(
|
|
3583
|
+
_cpp_decl_to_type(param.type, extra_types, opaque_classes=opaque_classes) for param in decl.parameters
|
|
3584
|
+
)
|
|
3585
|
+
param_names = (
|
|
3586
|
+
tuple(param.name.format() for param in decl.parameters) # type:ignore
|
|
3587
|
+
if all(param.name is not None for param in decl.parameters)
|
|
3588
|
+
else None
|
|
3589
|
+
)
|
|
3590
|
+
returnty = _cpp_decl_to_type(decl.return_type, extra_types, opaque_classes=opaque_classes)
|
|
3591
|
+
return SimTypeCppFunction(params, returnty, arg_names=param_names, convention=decl.msvc_convention)
|
|
3453
3592
|
|
|
3454
3593
|
raise NotImplementedError
|
|
3455
3594
|
|
|
3456
3595
|
|
|
3457
3596
|
def normalize_cpp_function_name(name: str) -> str:
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
s = re.sub(r"<[^<>]+>", "", _s)
|
|
3463
|
-
assert s is not None
|
|
3597
|
+
# strip access specifiers
|
|
3598
|
+
prefixes = ["public:", "protected:", "private:"]
|
|
3599
|
+
for pre in prefixes:
|
|
3600
|
+
name = name.removeprefix(pre)
|
|
3464
3601
|
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3602
|
+
if name.startswith("operator"):
|
|
3603
|
+
# the return type is missing; give it a default type
|
|
3604
|
+
name = "int " + name
|
|
3605
|
+
|
|
3606
|
+
return name.removesuffix(";")
|
|
3469
3607
|
|
|
3470
3608
|
|
|
3471
3609
|
def parse_cpp_file(cpp_decl, with_param_names: bool = False):
|
|
3472
3610
|
#
|
|
3473
|
-
# A series of hacks to make
|
|
3611
|
+
# A series of hacks to make cxxheaderparser happy with whatever C++ function prototypes we feed in
|
|
3474
3612
|
#
|
|
3475
3613
|
|
|
3476
|
-
if
|
|
3477
|
-
raise ImportError("Please install
|
|
3614
|
+
if cxxheaderparser is None:
|
|
3615
|
+
raise ImportError("Please install cxxheaderparser to parse C++ definitions")
|
|
3478
3616
|
|
|
3479
3617
|
# CppHeaderParser does not support specialization
|
|
3480
3618
|
s = normalize_cpp_function_name(cpp_decl)
|
|
3481
3619
|
|
|
3482
|
-
# CppHeaderParser does not like missing parameter names
|
|
3483
|
-
# FIXME: The following logic is only dealing with *one* C++ function declaration. Support multiple declarations
|
|
3484
|
-
# FIXME: when needed in the future.
|
|
3485
|
-
if not with_param_names:
|
|
3486
|
-
last_pos = 0
|
|
3487
|
-
i = 0
|
|
3488
|
-
while True:
|
|
3489
|
-
idx = s.find(",", last_pos)
|
|
3490
|
-
if idx == -1:
|
|
3491
|
-
break
|
|
3492
|
-
arg_name = f"a{i}"
|
|
3493
|
-
i += 1
|
|
3494
|
-
s = s[:idx] + " " + arg_name + s[idx:]
|
|
3495
|
-
last_pos = idx + len(arg_name) + 1 + 1
|
|
3496
|
-
|
|
3497
|
-
# the last parameter
|
|
3498
|
-
idx = s.find(")", last_pos)
|
|
3499
|
-
# TODO: consider the case where there are one or multiple spaces between ( and )
|
|
3500
|
-
if idx != -1 and s[idx - 1] != "(":
|
|
3501
|
-
arg_name = f"a{i}"
|
|
3502
|
-
s = s[:idx] + " " + arg_name + s[idx:]
|
|
3503
|
-
|
|
3504
3620
|
# CppHeaderParser does not like missing function body
|
|
3505
3621
|
s += "\n\n{}"
|
|
3506
3622
|
|
|
3507
3623
|
try:
|
|
3508
|
-
h =
|
|
3509
|
-
except
|
|
3510
|
-
|
|
3511
|
-
|
|
3624
|
+
h = cxxheaderparser.simple.parse_string(s)
|
|
3625
|
+
except cxxheaderparser.errors.CxxParseError:
|
|
3626
|
+
# GCC-mangled (and thus, demangled) function names do not have return types encoded; let's try to prefix s with
|
|
3627
|
+
# "void" and try again
|
|
3628
|
+
s = "void " + s
|
|
3629
|
+
try:
|
|
3630
|
+
h = cxxheaderparser.simple.parse_string(s)
|
|
3631
|
+
except cxxheaderparser.errors.CxxParseError:
|
|
3632
|
+
# if it still fails, we give up
|
|
3633
|
+
return None, None
|
|
3634
|
+
|
|
3635
|
+
if not h.namespace:
|
|
3512
3636
|
return None, None
|
|
3513
3637
|
|
|
3514
|
-
func_decls: dict[str, SimTypeCppFunction] = {}
|
|
3515
|
-
for the_func in h.functions:
|
|
3638
|
+
func_decls: dict[str, SimTypeCppFunction | SimTypeFunction] = {}
|
|
3639
|
+
for the_func in h.namespace.functions + h.namespace.method_impls:
|
|
3516
3640
|
# FIXME: We always assume that there is a "this" pointer but it is not the case for static methods.
|
|
3517
|
-
proto = cast(SimTypeCppFunction | None, _cpp_decl_to_type(the_func, {}, opaque_classes=True))
|
|
3518
|
-
if proto is not None
|
|
3519
|
-
func_name =
|
|
3520
|
-
proto
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
else:
|
|
3528
|
-
func_name = cast(str, the_func["name"])
|
|
3529
|
-
func_decls[func_name] = proto
|
|
3641
|
+
proto = cast(SimTypeCppFunction | SimTypeFunction | None, _cpp_decl_to_type(the_func, {}, opaque_classes=True))
|
|
3642
|
+
if proto is not None:
|
|
3643
|
+
func_name = the_func.name.format()
|
|
3644
|
+
if isinstance(proto, SimTypeCppFunction):
|
|
3645
|
+
proto.args = (
|
|
3646
|
+
SimTypePointer(pts_to=SimTypeBottom(label="void")),
|
|
3647
|
+
*proto.args,
|
|
3648
|
+
) # pylint:disable=attribute-defined-outside-init
|
|
3649
|
+
proto.arg_names = ("this", *proto.arg_names) # pylint:disable=attribute-defined-outside-init
|
|
3650
|
+
func_decls[func_name] = proto
|
|
3530
3651
|
|
|
3531
3652
|
return func_decls, {}
|
|
3532
3653
|
|