angr 9.2.148__py3-none-manylinux2014_x86_64.whl → 9.2.149__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 (55) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +42 -2
  3. angr/analyses/cfg/cfg_emulated.py +5 -2
  4. angr/analyses/cfg/cfg_fast.py +48 -46
  5. angr/analyses/decompiler/ail_simplifier.py +65 -32
  6. angr/analyses/decompiler/block_simplifier.py +20 -6
  7. angr/analyses/decompiler/clinic.py +80 -13
  8. angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
  9. angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
  10. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
  11. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
  12. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
  13. angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
  14. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
  15. angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
  16. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
  17. angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
  18. angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
  19. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  20. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
  21. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
  22. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
  23. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
  24. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
  25. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
  26. angr/analyses/decompiler/presets/fast.py +2 -0
  27. angr/analyses/decompiler/presets/full.py +2 -0
  28. angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
  29. angr/analyses/decompiler/ssailification/ssailification.py +23 -3
  30. angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
  31. angr/analyses/decompiler/structured_codegen/c.py +141 -10
  32. angr/analyses/decompiler/utils.py +6 -1
  33. angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
  34. angr/analyses/typehoon/lifter.py +20 -0
  35. angr/analyses/typehoon/simple_solver.py +42 -9
  36. angr/analyses/typehoon/translator.py +4 -1
  37. angr/analyses/typehoon/typeconsts.py +17 -6
  38. angr/analyses/typehoon/typehoon.py +21 -5
  39. angr/analyses/variable_recovery/engine_ail.py +44 -5
  40. angr/analyses/variable_recovery/engine_base.py +35 -12
  41. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
  42. angr/calling_conventions.py +23 -5
  43. angr/engines/light/engine.py +7 -0
  44. angr/knowledge_plugins/functions/function.py +68 -0
  45. angr/knowledge_plugins/propagations/states.py +5 -2
  46. angr/knowledge_plugins/variables/variable_manager.py +3 -3
  47. angr/procedures/definitions/__init__.py +1 -1
  48. angr/procedures/definitions/types_stl.py +22 -0
  49. angr/sim_type.py +251 -130
  50. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/METADATA +7 -7
  51. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/RECORD +55 -49
  52. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
  53. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/licenses/LICENSE +3 -0
  54. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
  55. {angr-9.2.148.dist-info → angr-9.2.149.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 CppHeaderParser
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(self, name=None, full=0, memo=None, indent=0):
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
- dict(self.fields),
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, pycparser.c_ast.FileAST):
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, pycparser.c_ast.FuncDef):
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, pycparser.c_ast.Decl):
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, pycparser.c_ast.Typedef):
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, pycparser.c_ast.Typename) and not isinstance(node, pycparser.c_ast.Decl):
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, pycparser.c_ast.FuncDecl):
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 pycparser.c_ast.EllipsisParam
3259
+ if type(x) is c_ast.EllipsisParam
3195
3260
  else (
3196
3261
  SimTypeBottom().with_arch(arch)
3197
- if type(x) is pycparser.c_ast.ID
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 pycparser.c_ast.EllipsisParam]
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, pycparser.c_ast.TypeDecl):
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, pycparser.c_ast.PtrDecl):
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, pycparser.c_ast.ArrayDecl):
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, pycparser.c_ast.Struct):
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, pycparser.c_ast.Union):
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, pycparser.c_ast.IdentifierType):
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, pycparser.c_ast.Enum):
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 pycparser.c_ast.Constant:
3415
+ if type(c) is c_ast.Constant:
3353
3416
  return int(c.value, base=0)
3354
- if type(c) is pycparser.c_ast.BinaryOp:
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 pycparser.c_ast.UnaryOp:
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 pycparser.c_ast.Cast:
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
- def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes=True):
3390
- if CppHeaderParser is None:
3391
- raise ImportError("Please install CppHeaderParser to parse C++ definitions")
3392
- if isinstance(decl, CppHeaderParser.CppMethod):
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["name"]
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["parameters"]:
3401
- arg_type = param["type"]
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["name"]
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 not the_func["returns"].strip():
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["returns"].strip(), extra_types, opaque_classes=opaque_classes)
3413
- # other properties
3414
- ctor = the_func["constructor"]
3415
- dtor = the_func["destructor"]
3416
- return SimTypeCppFunction(args, returnty, arg_names=arg_names_tuple, ctor=ctor, dtor=dtor)
3417
-
3418
- if isinstance(decl, str):
3419
- # a string that represents type
3420
- if decl.endswith("&"):
3421
- # reference
3422
- subdecl = decl.rstrip("&").strip()
3423
- subt = _cpp_decl_to_type(subdecl, extra_types, opaque_classes=opaque_classes)
3424
- return SimTypeReference(subt)
3425
-
3426
- if decl.endswith("*"):
3427
- # pointer
3428
- subdecl = decl.rstrip("*").strip()
3429
- subt = _cpp_decl_to_type(subdecl, extra_types, opaque_classes=opaque_classes)
3430
- return SimTypePointer(subt)
3431
-
3432
- if decl.endswith(" const"):
3433
- # drop const
3434
- return _cpp_decl_to_type(decl[:-6].strip(), extra_types, opaque_classes=opaque_classes)
3435
-
3436
- unqualified_name = decl.split("::")[-1] if "::" in decl else decl
3437
-
3438
- key = unqualified_name
3439
- if key in extra_types:
3440
- t = extra_types[key]
3441
- elif key in ALL_TYPES:
3442
- t = ALL_TYPES[key]
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({}, name=decl)
3556
+ t = SimCppClass(unique_name=lbl, name=lbl, members={})
3446
3557
  else:
3447
- raise TypeError("Unknown type '{}'".format(" ".join(key)))
3558
+ raise TypeError(f'Unknown type "{lbl}"')
3448
3559
 
3449
- if unqualified_name != decl and isinstance(t, NamedTypeMixin):
3560
+ if isinstance(t, NamedTypeMixin):
3450
3561
  t = t.copy()
3451
- t.name = decl # pylint:disable=attribute-defined-outside-init
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
- _s = name
3459
- s = None
3460
- while s != _s:
3461
- _s = s if s is not None else _s
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
- m = re.search(r"{([a-z\s]+)}", s)
3466
- if m is not None:
3467
- s = s[: m.start()] + "__" + m.group(1).replace(" ", "_") + "__" + s[m.end() :]
3468
- return s
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 CppHeaderParser happy with whatever C++ function prototypes we feed in
3611
+ # A series of hacks to make cxxheaderparser happy with whatever C++ function prototypes we feed in
3474
3612
  #
3475
3613
 
3476
- if CppHeaderParser is None:
3477
- raise ImportError("Please install CppHeaderParser to parse C++ definitions")
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 = CppHeaderParser.CppHeader(s, argType="string")
3509
- except CppHeaderParser.CppParseError:
3510
- return None, None
3511
- if not h.functions:
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 and the_func["class"]:
3519
- func_name = cast(str, the_func["class"] + "::" + the_func["name"])
3520
- proto.args = (
3521
- SimTypePointer(pts_to=SimTypeBottom(label="void")),
3522
- *proto.args,
3523
- ) # pylint:disable=attribute-defined-outside-init
3524
- proto.arg_names = ("this", *proto.arg_names) # pylint:disable=attribute-defined-outside-init
3525
- elif proto is None:
3526
- raise ValueError("proto is None but class is also None... not sure what this edge case means")
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: angr
3
- Version: 9.2.148
3
+ Version: 9.2.149
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  License: BSD-2-Clause
6
6
  Project-URL: Homepage, https://angr.io/
@@ -15,15 +15,15 @@ Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: CppHeaderParser
18
+ Requires-Dist: cxxheaderparser
19
19
  Requires-Dist: GitPython
20
- Requires-Dist: ailment==9.2.148
21
- Requires-Dist: archinfo==9.2.148
20
+ Requires-Dist: ailment==9.2.149
21
+ Requires-Dist: archinfo==9.2.149
22
22
  Requires-Dist: cachetools
23
23
  Requires-Dist: capstone==5.0.3
24
24
  Requires-Dist: cffi>=1.14.0
25
- Requires-Dist: claripy==9.2.148
26
- Requires-Dist: cle==9.2.148
25
+ Requires-Dist: claripy==9.2.149
26
+ Requires-Dist: cle==9.2.149
27
27
  Requires-Dist: mulpyplexer
28
28
  Requires-Dist: networkx!=2.8.1,>=2.0
29
29
  Requires-Dist: protobuf>=5.28.2
@@ -31,7 +31,7 @@ Requires-Dist: psutil
31
31
  Requires-Dist: pycparser>=2.18
32
32
  Requires-Dist: pydemumble
33
33
  Requires-Dist: pyformlang
34
- Requires-Dist: pyvex==9.2.148
34
+ Requires-Dist: pyvex==9.2.149
35
35
  Requires-Dist: rich>=13.1.0
36
36
  Requires-Dist: sortedcontainers
37
37
  Requires-Dist: sympy