angr 9.2.174__cp310-abi3-macosx_11_0_arm64.whl → 9.2.176__cp310-abi3-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.

Files changed (55) hide show
  1. angr/__init__.py +1 -1
  2. angr/__main__.py +32 -2
  3. angr/analyses/calling_convention/calling_convention.py +12 -0
  4. angr/analyses/cfg/cfg_base.py +1 -1
  5. angr/analyses/cfg/cfg_fast.py +27 -8
  6. angr/analyses/complete_calling_conventions.py +39 -26
  7. angr/analyses/decompiler/ail_simplifier.py +13 -11
  8. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +5 -1
  9. angr/analyses/decompiler/clinic.py +54 -40
  10. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
  11. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -2
  12. angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
  13. angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy.py → inlined_wcscpy.py} +16 -8
  14. angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy_consolidation.py → inlined_wcscpy_consolidation.py} +13 -13
  15. angr/analyses/decompiler/ssailification/rewriting_engine.py +14 -1
  16. angr/analyses/decompiler/structured_codegen/c.py +6 -5
  17. angr/analyses/decompiler/structuring/dream.py +2 -2
  18. angr/analyses/decompiler/structuring/phoenix.py +101 -23
  19. angr/analyses/decompiler/utils.py +1 -1
  20. angr/analyses/smc.py +1 -1
  21. angr/analyses/stack_pointer_tracker.py +4 -3
  22. angr/analyses/typehoon/lifter.py +29 -18
  23. angr/analyses/typehoon/simple_solver.py +157 -50
  24. angr/analyses/typehoon/translator.py +34 -34
  25. angr/analyses/typehoon/typeconsts.py +33 -15
  26. angr/analyses/typehoon/typevars.py +9 -2
  27. angr/analyses/variable_recovery/engine_ail.py +4 -2
  28. angr/analyses/variable_recovery/engine_base.py +4 -1
  29. angr/analyses/variable_recovery/variable_recovery_fast.py +3 -1
  30. angr/calling_conventions.py +2 -1
  31. angr/engines/icicle.py +4 -4
  32. angr/engines/vex/claripy/ccall.py +3 -3
  33. angr/knowledge_plugins/functions/function.py +18 -1
  34. angr/misc/bug_report.py +11 -2
  35. angr/procedures/definitions/__init__.py +88 -20
  36. angr/procedures/definitions/common/glibc.json +3516 -0
  37. angr/procedures/definitions/parse_glibc.py +78 -0
  38. angr/procedures/libc/fgets.py +2 -1
  39. angr/procedures/posix/pthread.py +4 -4
  40. angr/procedures/stubs/format_parser.py +3 -3
  41. angr/rustylib.abi3.so +0 -0
  42. angr/sim_type.py +73 -11
  43. angr/simos/windows.py +1 -1
  44. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +1 -1
  45. angr/unicornlib.dylib +0 -0
  46. angr/utils/constants.py +1 -1
  47. angr/utils/library.py +1 -0
  48. angr/utils/strings.py +20 -0
  49. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/METADATA +5 -5
  50. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/RECORD +54 -52
  51. angr/procedures/definitions/glibc.py +0 -8372
  52. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/WHEEL +0 -0
  53. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/entry_points.txt +0 -0
  54. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/licenses/LICENSE +0 -0
  55. {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,7 @@ All type constants used in type inference. They can be mapped, translated, or re
5
5
  from __future__ import annotations
6
6
 
7
7
  import functools
8
+ import itertools
8
9
 
9
10
 
10
11
  def memoize(f):
@@ -24,6 +25,9 @@ def memoize(f):
24
25
  class TypeConstant:
25
26
  SIZE = None
26
27
 
28
+ def __init__(self, name: str | None = None):
29
+ self.name = name
30
+
27
31
  def pp_str(self, mapping) -> str: # pylint:disable=unused-argument
28
32
  return repr(self)
29
33
 
@@ -115,7 +119,8 @@ class Int512(Int):
115
119
 
116
120
 
117
121
  class IntVar(Int):
118
- def __init__(self, size):
122
+ def __init__(self, size, name: str | None = None):
123
+ super().__init__(name)
119
124
  self._size = size
120
125
 
121
126
  @property
@@ -146,7 +151,8 @@ class Float64(Float):
146
151
 
147
152
 
148
153
  class Pointer(TypeConstant):
149
- def __init__(self, basetype: TypeConstant | None):
154
+ def __init__(self, basetype: TypeConstant | None, name: str | None = None):
155
+ super().__init__(name=name)
150
156
  self.basetype: TypeConstant | None = basetype
151
157
 
152
158
  def __eq__(self, other):
@@ -169,13 +175,15 @@ class Pointer32(Pointer, Int32):
169
175
  32-bit pointers.
170
176
  """
171
177
 
172
- def __init__(self, basetype=None):
173
- Pointer.__init__(self, basetype)
178
+ def __init__(self, basetype=None, name: str | None = None):
179
+ Pointer.__init__(self, basetype, name=name)
180
+ Int32.__init__(self, name=name)
174
181
 
175
182
  @memoize
176
183
  def __repr__(self, memo=None):
177
184
  bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
178
- return f"ptr32({bt})"
185
+ name_str = f"{self.name}#" if self.name else ""
186
+ return f"{name_str}ptr32({bt})"
179
187
 
180
188
 
181
189
  class Pointer64(Pointer, Int64):
@@ -183,17 +191,20 @@ class Pointer64(Pointer, Int64):
183
191
  64-bit pointers.
184
192
  """
185
193
 
186
- def __init__(self, basetype=None):
187
- Pointer.__init__(self, basetype)
194
+ def __init__(self, basetype=None, name: str | None = None):
195
+ Pointer.__init__(self, basetype, name=name)
196
+ Int64.__init__(self, name=name)
188
197
 
189
198
  @memoize
190
199
  def __repr__(self, memo=None):
191
200
  bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
192
- return f"ptr64({bt})"
201
+ name_str = f"{self.name}#" if self.name else ""
202
+ return f"{name_str}ptr64({bt})"
193
203
 
194
204
 
195
205
  class Array(TypeConstant):
196
- def __init__(self, element=None, count=None):
206
+ def __init__(self, element=None, count=None, name: str | None = None):
207
+ super().__init__(name=name)
197
208
  self.element: TypeConstant | None = element
198
209
  self.count: int | None = count
199
210
 
@@ -222,18 +233,22 @@ class Array(TypeConstant):
222
233
  return self._hash(set())
223
234
 
224
235
 
236
+ _STRUCT_ID = itertools.count()
237
+
238
+
225
239
  class Struct(TypeConstant):
226
- def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False):
240
+ def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False, idx: int = -1):
241
+ super().__init__(name=name)
227
242
  self.fields = {} if fields is None else fields # offset to type
228
- self.name = name
229
243
  self.field_names = field_names
230
244
  self.is_cppclass = is_cppclass
245
+ self.idx = idx if idx != -1 else next(_STRUCT_ID)
231
246
 
232
247
  def _hash(self, visited: set[int]):
233
248
  if id(self) in visited:
234
249
  return 0
235
250
  visited.add(id(self))
236
- return hash((type(self), self._hash_fields(visited)))
251
+ return hash((type(self), self.idx, self._hash_fields(visited)))
237
252
 
238
253
  def _hash_fields(self, visited: set[int]):
239
254
  keys = sorted(self.fields.keys())
@@ -252,6 +267,7 @@ class Struct(TypeConstant):
252
267
  @memoize
253
268
  def __repr__(self, memo=None):
254
269
  prefix = "CppClass" if self.is_cppclass else "struct"
270
+ prefix += f"#{self.idx}"
255
271
  if self.name:
256
272
  prefix = f"{prefix} {self.name}"
257
273
  return (
@@ -262,14 +278,15 @@ class Struct(TypeConstant):
262
278
  )
263
279
 
264
280
  def __eq__(self, other):
265
- return type(other) is type(self) and hash(self) == hash(other)
281
+ return type(other) is type(self) and self.idx == other.idx and hash(self) == hash(other)
266
282
 
267
283
  def __hash__(self):
268
284
  return self._hash(set())
269
285
 
270
286
 
271
287
  class Function(TypeConstant):
272
- def __init__(self, params: list, outputs: list):
288
+ def __init__(self, params: list, outputs: list, name: str | None = None):
289
+ super().__init__(name=name)
273
290
  self.params = params
274
291
  self.outputs = outputs
275
292
 
@@ -298,7 +315,8 @@ class Function(TypeConstant):
298
315
 
299
316
 
300
317
  class TypeVariableReference(TypeConstant):
301
- def __init__(self, typevar):
318
+ def __init__(self, typevar, name: str | None = None):
319
+ super().__init__(name=name)
302
320
  self.typevar = typevar
303
321
 
304
322
  def __repr__(self, memo=None):
@@ -559,20 +559,27 @@ class ReinterpretAs(BaseLabel):
559
559
 
560
560
 
561
561
  class HasField(BaseLabel):
562
+ """
563
+ Has a field of the given bit size * elem_count at the given offset.
564
+ """
565
+
562
566
  __slots__ = (
563
567
  "bits",
568
+ "elem_count",
564
569
  "offset",
565
570
  )
566
571
 
567
- def __init__(self, bits, offset):
572
+ def __init__(self, bits, offset, elem_count: int = 1):
568
573
  self.bits = bits
569
574
  self.offset = offset
575
+ self.elem_count = elem_count
570
576
  super().__init__()
571
577
 
572
578
  def __repr__(self):
573
579
  if self.bits == MAX_POINTSTO_BITS:
574
580
  return f"<MAX_POINTSTO_BITS>@{self.offset}"
575
- return f"<{self.bits} bits>@{self.offset}"
581
+ elem_str = str(self.elem_count) if self.elem_count != 1 else ""
582
+ return f"<{self.bits} bits>@{self.offset}{elem_str}"
576
583
 
577
584
 
578
585
  class IsArray(BaseLabel):
@@ -34,6 +34,7 @@ class SimEngineVRAIL(
34
34
  def __init__(
35
35
  self,
36
36
  *args,
37
+ type_lifter: TypeLifter,
37
38
  call_info=None,
38
39
  vvar_to_vvar: dict[int, int] | None,
39
40
  vvar_type_hints: dict[int, typeconsts.TypeConstant] | None = None,
@@ -44,6 +45,7 @@ class SimEngineVRAIL(
44
45
  self._reference_spoffset: bool = False
45
46
  self.call_info = call_info or {}
46
47
  self.vvar_to_vvar = vvar_to_vvar
48
+ self.type_lifter = type_lifter
47
49
 
48
50
  def _mapped_vvarid(self, vvar_id: int) -> int | None:
49
51
  if self.vvar_to_vvar is not None and vvar_id in self.vvar_to_vvar:
@@ -195,7 +197,7 @@ class SimEngineVRAIL(
195
197
  arg_type = (
196
198
  dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
197
199
  )
198
- arg_ty = TypeLifter(self.arch.bits).lift(arg_type)
200
+ arg_ty = self.type_lifter.lift(arg_type)
199
201
  type_constraint = typevars.Subtype(arg.typevar, arg_ty)
200
202
  self.state.add_type_constraint(type_constraint)
201
203
 
@@ -282,7 +284,7 @@ class SimEngineVRAIL(
282
284
  arg_type = (
283
285
  dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
284
286
  )
285
- arg_ty = TypeLifter(self.arch.bits).lift(arg_type)
287
+ arg_ty = self.type_lifter.lift(arg_type)
286
288
  if arg.typevar is not None and isinstance(
287
289
  arg_ty, (typeconsts.TypeConstant, typevars.TypeVariable, typevars.DerivedTypeVariable)
288
290
  ):
@@ -277,7 +277,10 @@ class SimEngineVRBase(
277
277
  variable, _ = existing_vars[0]
278
278
 
279
279
  if not self.state.typevars.has_type_variable_for(variable):
280
- variable_typevar = typevars.TypeVariable()
280
+ if isinstance(variable, SimStackVariable) and variable.offset in self.state.stack_offset_typevars:
281
+ variable_typevar = self.state.stack_offset_typevars[variable.offset]
282
+ else:
283
+ variable_typevar = typevars.TypeVariable()
281
284
  self.state.typevars.add_type_variable(variable, variable_typevar)
282
285
  # we do not add any type constraint here because we are not sure if the given memory address will ever be
283
286
  # accessed or not
@@ -284,6 +284,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
284
284
  self._unify_variables = unify_variables
285
285
 
286
286
  # handle type hints
287
+ self.type_lifter = TypeLifter(self.project.arch.bits)
287
288
  self.vvar_type_hints = {}
288
289
  if type_hints:
289
290
  self._parse_type_hints(type_hints)
@@ -294,6 +295,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
294
295
  call_info=call_info,
295
296
  vvar_to_vvar=self.vvar_to_vvar,
296
297
  vvar_type_hints=self.vvar_type_hints,
298
+ type_lifter=self.type_lifter,
297
299
  )
298
300
  self._vex_engine: SimEngineVRVEX = SimEngineVRVEX(self.project, self.kb, call_info=call_info)
299
301
 
@@ -654,7 +656,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
654
656
  if ty is None:
655
657
  return None
656
658
  ty = ty.with_arch(self.project.arch)
657
- lifted = TypeLifter(self.project.arch.bits).lift(ty)
659
+ lifted = self.type_lifter.lift(ty)
658
660
  return None if isinstance(lifted, (BottomType, TopType)) else lifted
659
661
 
660
662
 
@@ -34,6 +34,7 @@ from .sim_type import (
34
34
  SimTypeBottom,
35
35
  parse_signature,
36
36
  SimTypeReference,
37
+ SimTypeRef,
37
38
  )
38
39
  from .state_plugins.sim_action_object import SimActionObject
39
40
 
@@ -1430,7 +1431,7 @@ class SimCCMicrosoftAMD64(SimCC):
1430
1431
  return SimReferenceArgument(int_loc, referenced_loc)
1431
1432
 
1432
1433
  def return_in_implicit_outparam(self, ty):
1433
- if isinstance(ty, SimTypeBottom):
1434
+ if isinstance(ty, (SimTypeBottom, SimTypeRef)):
1434
1435
  return False
1435
1436
  return not isinstance(ty, SimTypeFloat) and ty.size > self.STRUCT_RETURN_THRESHOLD
1436
1437
 
angr/engines/icicle.py CHANGED
@@ -8,7 +8,7 @@ from dataclasses import dataclass
8
8
  from typing_extensions import override
9
9
 
10
10
  import pypcode
11
- from archinfo import Arch, Endness
11
+ from archinfo import Arch, Endness, ArchARMCortexM
12
12
 
13
13
  from angr.engines.concrete import ConcreteEngine, HeavyConcreteState
14
14
  from angr.engines.failure import SimEngineFailure
@@ -84,11 +84,11 @@ class IcicleEngine(ConcreteEngine):
84
84
  return icicle_arch.startswith(("arm", "thumb"))
85
85
 
86
86
  @staticmethod
87
- def __is_thumb(icicle_arch: str, addr: int) -> bool:
87
+ def __is_thumb(angr_arch: Arch, icicle_arch: str, addr: int) -> bool:
88
88
  """
89
89
  Check if the architecture is thumb based on the address.
90
90
  """
91
- return IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1
91
+ return isinstance(angr_arch, ArchARMCortexM) or (IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1)
92
92
 
93
93
  @staticmethod
94
94
  def __get_pages(state: HeavyConcreteState) -> set[int]:
@@ -138,7 +138,7 @@ class IcicleEngine(ConcreteEngine):
138
138
  log.debug("Register %s not found in icicle", register)
139
139
 
140
140
  # Unset the thumb bit if necessary
141
- if IcicleEngine.__is_thumb(icicle_arch, state.addr):
141
+ if IcicleEngine.__is_thumb(state.arch, icicle_arch, state.addr):
142
142
  emu.pc = state.addr & ~1
143
143
  emu.isa_mode = 1
144
144
  elif "arm" in icicle_arch: # Hack to work around us calling it r15t
@@ -343,7 +343,7 @@ def pc_make_rdata_if_necessary(nbits, cf, pf, af, zf, sf, of, platform=None):
343
343
 
344
344
 
345
345
  def pc_actions_ADD(state, nbits, arg_l, arg_r, cc_ndep, platform=None):
346
- data_mask, sign_mask = pc_preamble(nbits)
346
+ data_mask, _sign_mask = pc_preamble(nbits)
347
347
  res = arg_l + arg_r
348
348
 
349
349
  cf = claripy.If(claripy.ULT(res, arg_l), claripy.BVV(1, 1), claripy.BVV(0, 1))
@@ -701,7 +701,7 @@ def pc_calculate_rdata_all(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=Non
701
701
  def pc_calculate_condition(state, cond, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None):
702
702
  rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
703
703
  if isinstance(rdata_all, tuple):
704
- cf, pf, af, zf, sf, of = rdata_all
704
+ cf, pf, _af, zf, sf, of = rdata_all
705
705
  v = op_concretize(cond)
706
706
 
707
707
  inv = v & 1
@@ -993,7 +993,7 @@ def pc_calculate_rdata_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None)
993
993
  rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
994
994
 
995
995
  if isinstance(rdata_all, tuple):
996
- cf, pf, af, zf, sf, of = rdata_all
996
+ cf, _pf, _af, _zf, _sf, _of = rdata_all
997
997
  return claripy.Concat(claripy.BVV(0, data[platform]["size"] - 1), cf & 1)
998
998
  return claripy.LShR(rdata_all, data[platform]["CondBitOffsets"]["G_CC_SHIFT_C"]) & 1
999
999
 
@@ -1663,7 +1663,7 @@ class Function(Serializable):
1663
1663
 
1664
1664
  @property
1665
1665
  def demangled_name(self):
1666
- ast = pydemumble.demangle(self.name)
1666
+ ast = pydemumble.demangle(self.name).strip()
1667
1667
  if self.is_rust_function():
1668
1668
  nodes = ast.split("::")[:-1]
1669
1669
  ast = "::".join([Function._rust_fmt_node(node) for node in nodes])
@@ -1750,6 +1750,23 @@ class Function(Serializable):
1750
1750
  _find_called(self.addr)
1751
1751
  return {self._function_manager.function(a) for a in called}
1752
1752
 
1753
+ def holes(self, min_size: int = 8) -> int:
1754
+ """
1755
+ Find the number of non-consecutive areas in the function that are at least `min_size` bytes large.
1756
+ """
1757
+
1758
+ block_addrs = sorted(self._local_block_addrs)
1759
+ if not block_addrs:
1760
+ return 0
1761
+ holes = 0
1762
+ for i, addr in enumerate(block_addrs):
1763
+ if i == len(block_addrs) - 1:
1764
+ break
1765
+ next_addr = block_addrs[i + 1]
1766
+ if next_addr > addr + self._block_sizes[addr] and next_addr - (addr + self._block_sizes[addr]) >= min_size:
1767
+ holes += 1
1768
+ return holes
1769
+
1753
1770
  def copy(self):
1754
1771
  func = Function(self._function_manager, self.addr, name=self.name, syscall=self.is_syscall)
1755
1772
  func.transition_graph = networkx.DiGraph(self.transition_graph)
angr/misc/bug_report.py CHANGED
@@ -17,11 +17,20 @@ except ImportError:
17
17
  print("If you install gitpython (`pip install gitpython`), I can give you git info too!")
18
18
 
19
19
 
20
- angr_modules = ["angr", "ailment", "cle", "pyvex", "claripy", "archinfo", "z3", "unicorn"]
20
+ angr_modules = [
21
+ "angr",
22
+ "archinfo",
23
+ "claripy",
24
+ "cle",
25
+ "pypcode",
26
+ "pyvex",
27
+ "unicorn",
28
+ "z3",
29
+ ]
21
30
  native_modules = {
22
31
  "angr": lambda: angr.state_plugins.unicorn_engine._UC_NATIVE, # pylint: disable=undefined-variable
23
- "unicorn": lambda: unicorn.unicorn._uc, # pylint: disable=undefined-variable
24
32
  "pyvex": lambda: pyvex.pvc, # pylint: disable=undefined-variable
33
+ "unicorn": lambda: unicorn.unicorn._uc, # pylint: disable=undefined-variable
25
34
  "z3": lambda: next(x for x in gc.get_objects() if type(x) is ctypes.CDLL and "z3" in str(x)), # YIKES FOREVER
26
35
  }
27
36
  python_packages = {"z3": "z3-solver"}
@@ -161,13 +161,12 @@ class SimLibrary:
161
161
  for arch_name, cc_name in d["default_cc"].items():
162
162
  cc = CC_NAMES[cc_name]
163
163
  lib.set_default_cc(arch_name, cc)
164
- if "aliases" in d:
165
- for name, alt_names in d["aliases"].items():
166
- lib.add_alias(name, *alt_names)
167
164
  if "library_names" in d:
168
165
  lib.set_library_names(*d["library_names"])
169
166
  else:
170
167
  raise KeyError("library_names is required")
168
+ if "non_returning" in d:
169
+ lib.set_non_returning(*d["non_returning"])
171
170
  if "functions" in d:
172
171
  lib.prototypes_json = {k: v["proto"] for k, v in d["functions"].items() if "proto" in v}
173
172
  return lib
@@ -307,8 +306,8 @@ class SimLibrary:
307
306
  new_procedure = copy.deepcopy(old_procedure)
308
307
  new_procedure.display_name = alt
309
308
  self.procedures[alt] = new_procedure
310
- if name in self.prototypes:
311
- self.prototypes[alt] = self.prototypes[name]
309
+ if self.has_prototype(name):
310
+ self.prototypes[alt] = self.get_prototype(name) # type:ignore
312
311
  if name in self.non_returning:
313
312
  self.non_returning.add(alt)
314
313
 
@@ -317,8 +316,8 @@ class SimLibrary:
317
316
  proc.cc = self.default_ccs[arch.name](arch)
318
317
  if proc.cc is None and arch.name in self.fallback_cc:
319
318
  proc.cc = self.fallback_cc[arch.name]["Linux"](arch)
320
- if proc.display_name in self.prototypes:
321
- proc.prototype = self.prototypes[proc.display_name].with_arch(arch)
319
+ if self.has_prototype(proc.display_name):
320
+ proc.prototype = self.get_prototype(proc.display_name, deref=True).with_arch(arch) # type:ignore
322
321
  proc.guessed_prototype = False
323
322
  if proc.prototype.arg_names is None:
324
323
  # Use inspect to extract the parameters from the run python function
@@ -361,12 +360,13 @@ class SimLibrary:
361
360
  self._apply_metadata(proc, arch)
362
361
  return proc
363
362
 
364
- def get_prototype(self, name: str, arch=None) -> SimTypeFunction | None:
363
+ def get_prototype(self, name: str, arch=None, deref: bool = False) -> SimTypeFunction | None:
365
364
  """
366
365
  Get a prototype of the given function name, optionally specialize the prototype to a given architecture.
367
366
 
368
367
  :param name: Name of the function.
369
368
  :param arch: The architecture to specialize to.
369
+ :param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
370
370
  :return: Prototype of the function, or None if the prototype does not exist.
371
371
  """
372
372
  if name not in self.prototypes and name in self.prototypes_json:
@@ -389,6 +389,11 @@ class SimLibrary:
389
389
  proto = self.prototypes.get(name, None)
390
390
  if proto is None:
391
391
  return None
392
+ if deref:
393
+ from angr.utils.types import dereference_simtype_by_lib # pylint:disable=import-outside-toplevel
394
+
395
+ proto = dereference_simtype_by_lib(proto, self.name)
396
+ assert isinstance(proto, SimTypeFunction)
392
397
  if arch is not None:
393
398
  return proto.with_arch(arch)
394
399
  return proto
@@ -400,7 +405,7 @@ class SimLibrary:
400
405
  :param name: The name of the function as a string
401
406
  :return: A bool indicating if anything is known about the function
402
407
  """
403
- return self.has_implementation(name) or name in self.non_returning or name in self.prototypes
408
+ return self.has_implementation(name) or name in self.non_returning or self.has_prototype(name)
404
409
 
405
410
  def has_implementation(self, name):
406
411
  """
@@ -490,17 +495,18 @@ class SimCppLibrary(SimLibrary):
490
495
  stub.num_args = len(stub.prototype.args)
491
496
  return stub
492
497
 
493
- def get_prototype(self, name: str, arch=None) -> SimTypeFunction | None:
498
+ def get_prototype(self, name: str, arch=None, deref: bool = False) -> SimTypeFunction | None:
494
499
  """
495
500
  Get a prototype of the given function name, optionally specialize the prototype to a given architecture. The
496
501
  function name will be demangled first.
497
502
 
498
503
  :param name: Name of the function.
499
504
  :param arch: The architecture to specialize to.
505
+ :param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
500
506
  :return: Prototype of the function, or None if the prototype does not exist.
501
507
  """
502
508
  demangled_name = self._try_demangle(name)
503
- return super().get_prototype(demangled_name, arch=arch)
509
+ return super().get_prototype(demangled_name, arch=arch, deref=deref)
504
510
 
505
511
  def has_metadata(self, name):
506
512
  """
@@ -659,11 +665,39 @@ class SimSyscallLibrary(SimLibrary):
659
665
  if abi in self.default_cc_mapping:
660
666
  cc = self.default_cc_mapping[abi](arch)
661
667
  proc.cc = cc
668
+ elif arch.name in self.default_ccs:
669
+ proc.cc = self.default_ccs[arch.name](arch)
662
670
  # a bit of a hack.
663
671
  name = proc.display_name
664
- if self.syscall_prototypes[abi].get(name, None) is not None:
672
+ if self.has_prototype(abi, name):
665
673
  proc.guessed_prototype = False
666
- proc.prototype = self.syscall_prototypes[abi][name].with_arch(arch)
674
+ proto = self.get_prototype(abi, name, deref=True)
675
+ assert proto is not None
676
+ proc.prototype = proto.with_arch(arch)
677
+
678
+ def add_alias(self, name, *alt_names):
679
+ """
680
+ Add some duplicate names for a given function. The original function's implementation must already be
681
+ registered.
682
+
683
+ :param name: The name of the function for which an implementation is already present
684
+ :param alt_names: Any number of alternate names may be passed as varargs
685
+ """
686
+ old_procedure = self.procedures[name]
687
+ for alt in alt_names:
688
+ new_procedure = copy.deepcopy(old_procedure)
689
+ new_procedure.display_name = alt
690
+ self.procedures[alt] = new_procedure
691
+ for abi in self.syscall_prototypes:
692
+ if self.has_prototype(abi, name):
693
+ self.syscall_prototypes[abi][alt] = self.get_prototype(abi, name) # type:ignore
694
+ if name in self.non_returning:
695
+ self.non_returning.add(alt)
696
+
697
+ def _apply_metadata(self, proc, arch):
698
+ # this function is a no-op in SimSyscallLibrary; users are supposed to explicitly call
699
+ # _apply_numerical_metadata instead.
700
+ pass
667
701
 
668
702
  # pylint: disable=arguments-differ
669
703
  def get(self, number, arch, abi_list=()): # type:ignore
@@ -703,7 +737,9 @@ class SimSyscallLibrary(SimLibrary):
703
737
  l.debug("unsupported syscall: %s", number)
704
738
  return proc
705
739
 
706
- def get_prototype(self, abi: str, name: str, arch=None) -> SimTypeFunction | None: # type:ignore
740
+ def get_prototype( # type:ignore
741
+ self, abi: str, name: str, arch=None, deref: bool = False
742
+ ) -> SimTypeFunction | None:
707
743
  """
708
744
  Get a prototype of the given syscall name and its ABI, optionally specialize the prototype to a given
709
745
  architecture.
@@ -711,6 +747,7 @@ class SimSyscallLibrary(SimLibrary):
711
747
  :param abi: ABI of the prototype to get.
712
748
  :param name: Name of the syscall.
713
749
  :param arch: The architecture to specialize to.
750
+ :param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
714
751
  :return: Prototype of the syscall, or None if the prototype does not exist.
715
752
  """
716
753
  if abi not in self.syscall_prototypes:
@@ -718,6 +755,11 @@ class SimSyscallLibrary(SimLibrary):
718
755
  proto = self.syscall_prototypes[abi].get(name, None)
719
756
  if proto is None:
720
757
  return None
758
+ if deref:
759
+ from angr.utils.types import dereference_simtype_by_lib # pylint:disable=import-outside-toplevel
760
+
761
+ proto = dereference_simtype_by_lib(proto, self.name)
762
+ assert isinstance(proto, SimTypeFunction)
721
763
  return proto.with_arch(arch=arch)
722
764
 
723
765
  def has_metadata(self, number, arch, abi_list=()): # type:ignore
@@ -729,8 +771,10 @@ class SimSyscallLibrary(SimLibrary):
729
771
  :param abi_list: A list of ABI names that could be used
730
772
  :return: A bool of whether or not any implementation or metadata is known about the given syscall
731
773
  """
732
- name, _, _ = self._canonicalize(number, arch, abi_list)
733
- return super().has_metadata(name)
774
+ name, _, abi = self._canonicalize(number, arch, abi_list)
775
+ return (
776
+ name in self.procedures or name in self.non_returning or (abi is not None and self.has_prototype(abi, name))
777
+ )
734
778
 
735
779
  def has_implementation(self, number, arch, abi_list=()): # type:ignore
736
780
  """
@@ -879,7 +923,7 @@ def load_external_definitions():
879
923
 
880
924
 
881
925
  def _update_libkernel32(lib: SimLibrary):
882
- from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
926
+ from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
883
927
 
884
928
  lib.add_all_from_dict(P["win32"])
885
929
  lib.add_alias("EncodePointer", "DecodePointer")
@@ -895,7 +939,7 @@ def _update_libkernel32(lib: SimLibrary):
895
939
 
896
940
 
897
941
  def _update_libntdll(lib: SimLibrary):
898
- from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
942
+ from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
899
943
 
900
944
  lib.add("RtlEncodePointer", P["win32"]["EncodePointer"])
901
945
  lib.add("RtlDecodePointer", P["win32"]["EncodePointer"])
@@ -903,7 +947,7 @@ def _update_libntdll(lib: SimLibrary):
903
947
 
904
948
 
905
949
  def _update_libuser32(lib: SimLibrary):
906
- from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
950
+ from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
907
951
  from angr.calling_conventions import SimCCCdecl # pylint:disable=import-outside-toplevel
908
952
 
909
953
  lib.add_all_from_dict(P["win_user32"])
@@ -911,11 +955,33 @@ def _update_libuser32(lib: SimLibrary):
911
955
 
912
956
 
913
957
  def _update_libntoskrnl(lib: SimLibrary):
914
- from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
958
+ from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
915
959
 
916
960
  lib.add_all_from_dict(P["win32_kernel"])
917
961
 
918
962
 
963
+ def _update_glibc(libc: SimLibrary):
964
+ from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
965
+
966
+ libc.add_all_from_dict(P["libc"])
967
+ libc.add_all_from_dict(P["posix"])
968
+ libc.add_all_from_dict(P["glibc"])
969
+ # gotta do this since there's no distinguishing different libcs without analysis. there should be no naming
970
+ # conflicts in the functions.
971
+ libc.add_all_from_dict(P["uclibc"])
972
+
973
+ # aliases for SimProcedures
974
+ libc.add_alias("abort", "__assert_fail", "__stack_chk_fail")
975
+ libc.add_alias("memcpy", "memmove", "bcopy")
976
+ libc.add_alias("getc", "_IO_getc")
977
+ libc.add_alias("putc", "_IO_putc")
978
+ libc.add_alias("gets", "_IO_gets")
979
+ libc.add_alias("puts", "_IO_puts")
980
+ libc.add_alias("exit", "_exit", "_Exit")
981
+ libc.add_alias("sprintf", "siprintf")
982
+ libc.add_alias("snprintf", "sniprintf")
983
+
984
+
919
985
  def load_win32api_definitions():
920
986
  load_win32_type_collections()
921
987
  if once("load_win32api_definitions"):
@@ -961,4 +1027,6 @@ load_type_collections(skip={"win32"})
961
1027
 
962
1028
 
963
1029
  # Load common definitions
1030
+ _load_definitions(os.path.join(_DEFINITIONS_BASEDIR, "common"), only=COMMON_LIBRARIES)
964
1031
  _load_definitions(_DEFINITIONS_BASEDIR, only=COMMON_LIBRARIES)
1032
+ _update_glibc(SIM_LIBRARIES["libc.so"][0])