angr 9.2.87__py3-none-manylinux2014_x86_64.whl → 9.2.89__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 (248) hide show
  1. angr/__init__.py +4 -1
  2. angr/analyses/decompiler/clinic.py +16 -0
  3. angr/analyses/decompiler/decompiler.py +3 -0
  4. angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
  5. angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +108 -0
  6. angr/analyses/decompiler/optimization_passes/optimization_pass.py +17 -4
  7. angr/analyses/decompiler/optimization_passes/return_duplicator.py +4 -32
  8. angr/analyses/decompiler/structured_codegen/c.py +12 -2
  9. angr/analyses/decompiler/utils.py +13 -0
  10. angr/analyses/typehoon/dfa.py +108 -0
  11. angr/analyses/typehoon/lifter.py +34 -2
  12. angr/analyses/typehoon/simple_solver.py +1043 -503
  13. angr/analyses/typehoon/translator.py +13 -4
  14. angr/analyses/typehoon/typeconsts.py +117 -36
  15. angr/analyses/typehoon/typehoon.py +31 -11
  16. angr/analyses/typehoon/typevars.py +88 -21
  17. angr/analyses/typehoon/variance.py +10 -0
  18. angr/analyses/variable_recovery/engine_ail.py +28 -9
  19. angr/analyses/variable_recovery/engine_base.py +50 -43
  20. angr/analyses/variable_recovery/variable_recovery_base.py +16 -3
  21. angr/analyses/variable_recovery/variable_recovery_fast.py +14 -5
  22. angr/exploration_techniques/tracer.py +2 -0
  23. angr/misc/autoimport.py +26 -0
  24. angr/procedures/definitions/__init__.py +32 -3
  25. angr/utils/constants.py +1 -0
  26. angr/utils/graph.py +20 -1
  27. {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/METADATA +7 -6
  28. {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/RECORD +32 -244
  29. angr-9.2.89.dist-info/top_level.txt +1 -0
  30. angr/procedures/definitions/ntdll.py +0 -12
  31. angr-9.2.87.dist-info/top_level.txt +0 -2
  32. tests/__init__.py +0 -0
  33. tests/analyses/__init__.py +0 -0
  34. tests/analyses/cfg/__init__.py +0 -0
  35. tests/analyses/cfg/test_cfg_clflush.py +0 -43
  36. tests/analyses/cfg/test_cfg_get_any_node.py +0 -34
  37. tests/analyses/cfg/test_cfg_manager.py +0 -32
  38. tests/analyses/cfg/test_cfg_model.py +0 -55
  39. tests/analyses/cfg/test_cfg_patching.py +0 -378
  40. tests/analyses/cfg/test_cfg_rust_got_resolution.py +0 -36
  41. tests/analyses/cfg/test_cfg_thumb_firmware.py +0 -50
  42. tests/analyses/cfg/test_cfg_vex_postprocessor.py +0 -27
  43. tests/analyses/cfg/test_cfgemulated.py +0 -634
  44. tests/analyses/cfg/test_cfgfast.py +0 -1123
  45. tests/analyses/cfg/test_cfgfast_soot.py +0 -38
  46. tests/analyses/cfg/test_const_resolver.py +0 -38
  47. tests/analyses/cfg/test_iat_resolver.py +0 -37
  48. tests/analyses/cfg/test_jumptables.py +0 -3008
  49. tests/analyses/cfg/test_noop_blocks.py +0 -54
  50. tests/analyses/cfg_slice_to_sink/__init__.py +0 -0
  51. tests/analyses/cfg_slice_to_sink/test_cfg_slice_to_sink.py +0 -93
  52. tests/analyses/cfg_slice_to_sink/test_graph.py +0 -114
  53. tests/analyses/cfg_slice_to_sink/test_transitions.py +0 -28
  54. tests/analyses/decompiler/__init__.py +0 -0
  55. tests/analyses/decompiler/test_baseptr_save_simplifier.py +0 -80
  56. tests/analyses/decompiler/test_decompiler.py +0 -3336
  57. tests/analyses/decompiler/test_peephole_optimizations.py +0 -48
  58. tests/analyses/decompiler/test_propagator_loops.py +0 -101
  59. tests/analyses/decompiler/test_structurer.py +0 -275
  60. tests/analyses/reaching_definitions/__init__.py +0 -0
  61. tests/analyses/reaching_definitions/test_dep_graph.py +0 -432
  62. tests/analyses/reaching_definitions/test_function_handler.py +0 -131
  63. tests/analyses/reaching_definitions/test_heap_allocator.py +0 -46
  64. tests/analyses/reaching_definitions/test_rd_state.py +0 -78
  65. tests/analyses/reaching_definitions/test_reachingdefinitions.py +0 -463
  66. tests/analyses/reaching_definitions/test_subject.py +0 -76
  67. tests/analyses/test_bindiff.py +0 -52
  68. tests/analyses/test_block_simplifier.py +0 -112
  69. tests/analyses/test_boyscout.py +0 -104
  70. tests/analyses/test_calling_convention_analysis.py +0 -352
  71. tests/analyses/test_callsite_maker.py +0 -60
  72. tests/analyses/test_cdg.py +0 -165
  73. tests/analyses/test_cfb.py +0 -37
  74. tests/analyses/test_class_identifier.py +0 -46
  75. tests/analyses/test_clinic.py +0 -30
  76. tests/analyses/test_codetagging.py +0 -32
  77. tests/analyses/test_constantpropagation.py +0 -88
  78. tests/analyses/test_ddg.py +0 -95
  79. tests/analyses/test_ddg_global_var_dependencies.py +0 -83
  80. tests/analyses/test_ddg_memvar_addresses.py +0 -40
  81. tests/analyses/test_disassembly.py +0 -121
  82. tests/analyses/test_find_objects_static.py +0 -35
  83. tests/analyses/test_flirt.py +0 -49
  84. tests/analyses/test_identifier.py +0 -33
  85. tests/analyses/test_init_finder.py +0 -38
  86. tests/analyses/test_proximitygraph.py +0 -31
  87. tests/analyses/test_reassembler.py +0 -295
  88. tests/analyses/test_regionidentifier.py +0 -27
  89. tests/analyses/test_slicing.py +0 -164
  90. tests/analyses/test_stack_pointer_tracker.py +0 -74
  91. tests/analyses/test_static_hooker.py +0 -28
  92. tests/analyses/test_typehoon.py +0 -55
  93. tests/analyses/test_variablerecovery.py +0 -464
  94. tests/analyses/test_vfg.py +0 -221
  95. tests/analyses/test_vtable.py +0 -31
  96. tests/analyses/test_xrefs.py +0 -77
  97. tests/common.py +0 -128
  98. tests/engines/__init__.py +0 -0
  99. tests/engines/light/__init__.py +0 -0
  100. tests/engines/light/test_data.py +0 -17
  101. tests/engines/pcode/__init__.py +0 -0
  102. tests/engines/pcode/test_emulate.py +0 -607
  103. tests/engines/pcode/test_pcode.py +0 -84
  104. tests/engines/test_actions.py +0 -27
  105. tests/engines/test_hook.py +0 -112
  106. tests/engines/test_java.py +0 -697
  107. tests/engines/test_unicorn.py +0 -518
  108. tests/engines/vex/__init__.py +0 -0
  109. tests/engines/vex/test_lifter.py +0 -124
  110. tests/engines/vex/test_vex.py +0 -574
  111. tests/exploration_techniques/__init__.py +0 -0
  112. tests/exploration_techniques/test_cacher.py +0 -45
  113. tests/exploration_techniques/test_director.py +0 -67
  114. tests/exploration_techniques/test_driller_core.py +0 -48
  115. tests/exploration_techniques/test_loop_seer.py +0 -158
  116. tests/exploration_techniques/test_memory_watcher.py +0 -46
  117. tests/exploration_techniques/test_oppologist.py +0 -65
  118. tests/exploration_techniques/test_spiller.py +0 -82
  119. tests/exploration_techniques/test_stochastic.py +0 -40
  120. tests/exploration_techniques/test_tech_builder.py +0 -61
  121. tests/exploration_techniques/test_tracer.py +0 -856
  122. tests/exploration_techniques/test_unique.py +0 -40
  123. tests/exploration_techniques/test_veritesting.py +0 -120
  124. tests/factory/__init__.py +0 -0
  125. tests/factory/block/__init__.py +0 -0
  126. tests/factory/block/test_block_cache.py +0 -33
  127. tests/factory/block/test_keystone.py +0 -106
  128. tests/factory/test_argc.py +0 -101
  129. tests/factory/test_argc_sym.py +0 -110
  130. tests/factory/test_argv.py +0 -158
  131. tests/factory/test_callable.py +0 -266
  132. tests/factory/test_windows_args.py +0 -36
  133. tests/knowledge_plugins/__init__.py +0 -0
  134. tests/knowledge_plugins/cfg/__init__.py +0 -0
  135. tests/knowledge_plugins/cfg/test_cfg_manager.py +0 -36
  136. tests/knowledge_plugins/functions/__init__.py +0 -0
  137. tests/knowledge_plugins/functions/test_function.py +0 -91
  138. tests/knowledge_plugins/functions/test_function2.py +0 -79
  139. tests/knowledge_plugins/functions/test_function_manager.py +0 -139
  140. tests/knowledge_plugins/functions/test_prototypes.py +0 -53
  141. tests/knowledge_plugins/key_definitions/__init__.py +0 -0
  142. tests/knowledge_plugins/key_definitions/test_atoms.py +0 -24
  143. tests/knowledge_plugins/key_definitions/test_environment.py +0 -126
  144. tests/knowledge_plugins/key_definitions/test_heap_address.py +0 -27
  145. tests/knowledge_plugins/key_definitions/test_live_definitions.py +0 -72
  146. tests/knowledge_plugins/test_dwarf_variables.py +0 -240
  147. tests/knowledge_plugins/test_kb_plugins.py +0 -91
  148. tests/knowledge_plugins/test_kb_plugins_dwarf.py +0 -36
  149. tests/knowledge_plugins/test_patches.py +0 -48
  150. tests/misc/__init__.py +0 -0
  151. tests/misc/test_hookset.py +0 -57
  152. tests/perf/__init__.py +0 -0
  153. tests/perf/perf_cfgemulated.py +0 -19
  154. tests/perf/perf_cfgfast.py +0 -18
  155. tests/perf/perf_concrete_execution.py +0 -41
  156. tests/perf/perf_siminspect_nop.py +0 -36
  157. tests/perf/perf_state_copy.py +0 -33
  158. tests/perf/perf_unicorn_0.py +0 -27
  159. tests/perf/perf_unicorn_1.py +0 -23
  160. tests/procedures/__init__.py +0 -0
  161. tests/procedures/glibc/__init__.py +0 -0
  162. tests/procedures/glibc/test_ctype_locale.py +0 -164
  163. tests/procedures/libc/__init__.py +0 -0
  164. tests/procedures/libc/test_fgets.py +0 -53
  165. tests/procedures/libc/test_scanf.py +0 -205
  166. tests/procedures/libc/test_sprintf.py +0 -44
  167. tests/procedures/libc/test_sscanf.py +0 -63
  168. tests/procedures/libc/test_strcasecmp.py +0 -37
  169. tests/procedures/libc/test_string.py +0 -1102
  170. tests/procedures/libc/test_strtol.py +0 -78
  171. tests/procedures/linux_kernel/__init__.py +0 -0
  172. tests/procedures/linux_kernel/test_lseek.py +0 -174
  173. tests/procedures/posix/__init__.py +0 -0
  174. tests/procedures/posix/test_chroot.py +0 -33
  175. tests/procedures/posix/test_getenv.py +0 -78
  176. tests/procedures/posix/test_pwrite_pread.py +0 -57
  177. tests/procedures/posix/test_sim_time.py +0 -46
  178. tests/procedures/posix/test_unlink.py +0 -46
  179. tests/procedures/test_project_resolve_simproc.py +0 -43
  180. tests/procedures/test_sim_procedure.py +0 -117
  181. tests/procedures/test_stub_procedure_args.py +0 -53
  182. tests/serialization/__init__.py +0 -0
  183. tests/serialization/test_db.py +0 -197
  184. tests/serialization/test_pickle.py +0 -95
  185. tests/serialization/test_serialization.py +0 -132
  186. tests/serialization/test_vault.py +0 -169
  187. tests/sim/__init__.py +0 -3
  188. tests/sim/exec_func/__init__.py +0 -0
  189. tests/sim/exec_func/test_mem_funcs.py +0 -55
  190. tests/sim/exec_func/test_str_funcs.py +0 -93
  191. tests/sim/exec_func/test_syscall_result.py +0 -39
  192. tests/sim/exec_insn/__init__.py +0 -0
  193. tests/sim/exec_insn/test_adc.py +0 -44
  194. tests/sim/exec_insn/test_ops.py +0 -83
  195. tests/sim/exec_insn/test_rcr.py +0 -26
  196. tests/sim/exec_insn/test_rol.py +0 -51
  197. tests/sim/exec_insn/test_signed_div.py +0 -34
  198. tests/sim/exec_insn/test_sqrt.py +0 -56
  199. tests/sim/options/__init__.py +0 -0
  200. tests/sim/options/test_0div.py +0 -54
  201. tests/sim/options/test_symbolic_fd.py +0 -59
  202. tests/sim/options/test_unsupported.py +0 -34
  203. tests/sim/test_accuracy.py +0 -137
  204. tests/sim/test_checkbyte.py +0 -53
  205. tests/sim/test_echo.py +0 -36
  206. tests/sim/test_fauxware.py +0 -202
  207. tests/sim/test_self_modifying_code.py +0 -65
  208. tests/sim/test_simple_api.py +0 -36
  209. tests/sim/test_simulation_manager.py +0 -147
  210. tests/sim/test_stack_alignment.py +0 -65
  211. tests/sim/test_state.py +0 -303
  212. tests/sim/test_state_customization.py +0 -54
  213. tests/sim/test_symbol_hooked_by.py +0 -49
  214. tests/simos/__init__.py +0 -0
  215. tests/simos/windows/__init__.py +0 -0
  216. tests/simos/windows/test_windows_stack_cookie.py +0 -58
  217. tests/state_plugins/__init__.py +0 -0
  218. tests/state_plugins/inspect/__init__.py +0 -0
  219. tests/state_plugins/inspect/test_inspect.py +0 -310
  220. tests/state_plugins/inspect/test_syscall_override.py +0 -90
  221. tests/state_plugins/posix/__init__.py +0 -0
  222. tests/state_plugins/posix/test_file_struct_funcs.py +0 -56
  223. tests/state_plugins/posix/test_files.py +0 -69
  224. tests/state_plugins/posix/test_posix.py +0 -72
  225. tests/state_plugins/solver/__init__.py +0 -0
  226. tests/state_plugins/solver/test_simsolver.py +0 -58
  227. tests/state_plugins/solver/test_symbolic.py +0 -153
  228. tests/state_plugins/solver/test_variable_registration.py +0 -46
  229. tests/state_plugins/test_callstack.py +0 -54
  230. tests/state_plugins/test_gdb_plugin.py +0 -35
  231. tests/state_plugins/test_multi_open_file.py +0 -47
  232. tests/state_plugins/test_symbolization.py +0 -38
  233. tests/storage/__init__.py +0 -0
  234. tests/storage/test_memory.py +0 -960
  235. tests/storage/test_memory_merge.py +0 -114
  236. tests/storage/test_memview.py +0 -205
  237. tests/storage/test_mmap.py +0 -26
  238. tests/storage/test_multivalues.py +0 -44
  239. tests/storage/test_permissions.py +0 -32
  240. tests/storage/test_ptmalloc.py +0 -291
  241. tests/storage/test_relro_perm.py +0 -49
  242. tests/test_calling_conventions.py +0 -86
  243. tests/test_types.py +0 -329
  244. tests/utils/__init__.py +0 -0
  245. tests/utils/test_graph.py +0 -41
  246. {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/LICENSE +0 -0
  247. {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/WHEEL +0 -0
  248. {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/entry_points.txt +0 -0
@@ -91,15 +91,20 @@ class TypeTranslator:
91
91
  internal = self._tc2simtype(tc.basetype)
92
92
  return sim_type.SimTypePointer(internal).with_arch(self.arch)
93
93
 
94
- def _translate_Array(self, tc: typeconsts.Array):
94
+ def _translate_Array(self, tc: typeconsts.Array) -> sim_type.SimTypeArray:
95
95
  elem_type = self._tc2simtype(tc.element)
96
96
  return sim_type.SimTypeArray(elem_type, length=tc.count).with_arch(self.arch)
97
97
 
98
- def _translate_Struct(self, tc):
98
+ def _translate_Struct(self, tc: typeconsts.Struct):
99
99
  if tc in self.structs:
100
100
  return self.structs[tc]
101
101
 
102
- s = sim_type.SimStruct({}, name=self.struct_name()).with_arch(self.arch)
102
+ if tc.name:
103
+ name = tc.name
104
+ else:
105
+ name = self.struct_name()
106
+
107
+ s = sim_type.SimStruct({}, name=name).with_arch(self.arch)
103
108
  self.structs[tc] = s
104
109
 
105
110
  next_offset = 0
@@ -117,7 +122,11 @@ class TypeTranslator:
117
122
  # for now, we replace it with an unsigned char
118
123
  translated_type = sim_type.SimTypeChar(signed=False).with_arch(self.arch)
119
124
 
120
- s.fields["field_%x" % offset] = translated_type
125
+ if tc.field_names and offset in tc.field_names:
126
+ field_name = tc.field_names[offset]
127
+ else:
128
+ field_name = f"field_{offset:x}"
129
+ s.fields[field_name] = translated_type
121
130
 
122
131
  if isinstance(translated_type, SimTypeTempRef):
123
132
  next_offset = self.arch.bytes + offset
@@ -3,7 +3,25 @@
3
3
  All type constants used in type inference. They can be mapped, translated, or rewritten to C-style types.
4
4
  """
5
5
 
6
- from typing import Optional
6
+ from typing import List, Optional, Set
7
+ import functools
8
+
9
+
10
+ def memoize(f):
11
+ @functools.wraps(f)
12
+ def wrapped_repr(self, *args, **kwargs):
13
+ if not kwargs or "memo" not in kwargs:
14
+ memo = set()
15
+ else:
16
+ memo = kwargs.pop("memo")
17
+ if self in memo:
18
+ return "..."
19
+ memo.add(self)
20
+ r = f(self, *args, memo=memo, **kwargs)
21
+ memo.remove(self)
22
+ return r
23
+
24
+ return wrapped_repr
7
25
 
8
26
 
9
27
  class TypeConstant:
@@ -12,11 +30,14 @@ class TypeConstant:
12
30
  def pp_str(self, mapping) -> str: # pylint:disable=unused-argument
13
31
  return repr(self)
14
32
 
33
+ def _hash(self, visited: Set[int]): # pylint:disable=unused-argument
34
+ return hash(type(self))
35
+
15
36
  def __eq__(self, other):
16
- return type(self) == type(other)
37
+ return type(self) is type(other)
17
38
 
18
39
  def __hash__(self):
19
- return hash(type(self))
40
+ return self._hash(set())
20
41
 
21
42
  @property
22
43
  def size(self) -> int:
@@ -24,19 +45,22 @@ class TypeConstant:
24
45
  raise NotImplementedError()
25
46
  return self.SIZE
26
47
 
48
+ def __repr__(self, memo=None):
49
+ raise NotImplementedError()
50
+
27
51
 
28
52
  class TopType(TypeConstant):
29
- def __repr__(self):
53
+ def __repr__(self, memo=None):
30
54
  return "TOP"
31
55
 
32
56
 
33
57
  class BottomType(TypeConstant):
34
- def __repr__(self):
58
+ def __repr__(self, memo=None):
35
59
  return "BOT"
36
60
 
37
61
 
38
62
  class Int(TypeConstant):
39
- def __repr__(self):
63
+ def __repr__(self, memo=None):
40
64
  return "intbase"
41
65
 
42
66
 
@@ -47,81 +71,88 @@ class Int1(Int):
47
71
  class Int8(Int):
48
72
  SIZE = 1
49
73
 
50
- def __repr__(self):
74
+ def __repr__(self, memo=None):
51
75
  return "int8"
52
76
 
53
77
 
54
78
  class Int16(Int):
55
79
  SIZE = 2
56
80
 
57
- def __repr__(self):
81
+ def __repr__(self, memo=None):
58
82
  return "int16"
59
83
 
60
84
 
61
85
  class Int32(Int):
62
86
  SIZE = 4
63
87
 
64
- def __repr__(self):
88
+ def __repr__(self, memo=None):
65
89
  return "int32"
66
90
 
67
91
 
68
92
  class Int64(Int):
69
93
  SIZE = 8
70
94
 
71
- def __repr__(self):
95
+ def __repr__(self, memo=None):
72
96
  return "int64"
73
97
 
74
98
 
75
99
  class Int128(Int):
76
100
  SIZE = 16
77
101
 
78
- def __repr__(self):
102
+ def __repr__(self, memo=None):
79
103
  return "int128"
80
104
 
81
105
 
82
106
  class FloatBase(TypeConstant):
83
- def __repr__(self):
107
+ def __repr__(self, memo=None):
84
108
  return "floatbase"
85
109
 
86
110
 
87
111
  class Float(FloatBase):
88
112
  SIZE = 4
89
113
 
90
- def __repr__(self):
114
+ def __repr__(self, memo=None):
91
115
  return "float"
92
116
 
93
117
 
94
118
  class Double(FloatBase):
95
119
  SIZE = 8
96
120
 
97
- def __repr__(self):
121
+ def __repr__(self, memo=None):
98
122
  return "double"
99
123
 
100
124
 
101
125
  class Pointer(TypeConstant):
102
- def __init__(self, basetype):
103
- self.basetype = basetype
126
+ def __init__(self, basetype: Optional[TypeConstant]):
127
+ self.basetype: Optional[TypeConstant] = basetype
104
128
 
105
129
  def __eq__(self, other):
106
130
  return type(self) is type(other) and self.basetype == other.basetype
107
131
 
108
- def __hash__(self):
109
- return hash((type(self), hash(self.basetype)))
132
+ def _hash(self, visited: Set[int]):
133
+ if self.basetype is None:
134
+ return hash(type(self))
135
+ return hash((type(self), self.basetype._hash(visited)))
110
136
 
111
137
  def new(self, basetype):
112
138
  return self.__class__(basetype)
113
139
 
140
+ def __hash__(self):
141
+ return self._hash(set())
142
+
114
143
 
115
144
  class Pointer32(Pointer, Int32):
116
145
  """
117
146
  32-bit pointers.
118
147
  """
119
148
 
120
- def __init__(self, basetype):
149
+ def __init__(self, basetype=None):
121
150
  Pointer.__init__(self, basetype)
122
151
 
123
- def __repr__(self):
124
- return "ptr32(%r)" % self.basetype
152
+ @memoize
153
+ def __repr__(self, memo=None):
154
+ bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
155
+ return f"ptr32({bt})"
125
156
 
126
157
 
127
158
  class Pointer64(Pointer, Int64):
@@ -129,19 +160,22 @@ class Pointer64(Pointer, Int64):
129
160
  64-bit pointers.
130
161
  """
131
162
 
132
- def __init__(self, basetype):
163
+ def __init__(self, basetype=None):
133
164
  Pointer.__init__(self, basetype)
134
165
 
135
- def __repr__(self):
136
- return "ptr64(%r)" % self.basetype
166
+ @memoize
167
+ def __repr__(self, memo=None):
168
+ bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
169
+ return f"ptr64({bt})"
137
170
 
138
171
 
139
172
  class Array(TypeConstant):
140
- def __init__(self, element, count=None):
141
- self.element: TypeConstant = element
173
+ def __init__(self, element=None, count=None):
174
+ self.element: Optional[TypeConstant] = element
142
175
  self.count: Optional[int] = count
143
176
 
144
- def __repr__(self):
177
+ @memoize
178
+ def __repr__(self, memo=None):
145
179
  if self.count is None:
146
180
  return "%r[?]" % self.element
147
181
  else:
@@ -150,34 +184,81 @@ class Array(TypeConstant):
150
184
  def __eq__(self, other):
151
185
  return type(other) is type(self) and self.element == other.element and self.count == other.count
152
186
 
153
- def __hash__(self):
187
+ def _hash(self, visited: Set[int]):
188
+ if id(self) in visited:
189
+ return 0
190
+ visited.add(id(self))
154
191
  return hash((type(self), self.element, self.count))
155
192
 
193
+ def __hash__(self):
194
+ return self._hash(set())
195
+
156
196
 
157
197
  class Struct(TypeConstant):
158
- def __init__(self, fields=None):
198
+ def __init__(self, fields=None, name=None, field_names=None):
159
199
  self.fields = {} if fields is None else fields # offset to type
200
+ self.name = name
201
+ self.field_names = field_names
202
+
203
+ def _hash(self, visited: Set[int]):
204
+ if id(self) in visited:
205
+ return 0
206
+ visited.add(id(self))
207
+ return hash((type(self), self._hash_fields(visited)))
160
208
 
161
- def _hash_fields(self):
209
+ def _hash_fields(self, visited: Set[int]):
162
210
  keys = sorted(self.fields.keys())
163
- tpl = tuple((k, self.fields[k]) for k in keys)
211
+ tpl = tuple((k, self.fields[k]._hash(visited)) for k in keys)
164
212
  return hash(tpl)
165
213
 
166
- def __repr__(self):
167
- return "struct%r" % self.fields
214
+ @memoize
215
+ def __repr__(self, memo=None):
216
+ prefix = "struct"
217
+ if self.name:
218
+ prefix = f"struct {self.name}"
219
+ return prefix + "{" + ", ".join(f"{k}:{v.__repr__(memo=memo)}" for k, v in self.fields.items()) + "}"
220
+
221
+ def __eq__(self, other):
222
+ return type(other) is type(self) and hash(self) == hash(other)
223
+
224
+ def __hash__(self):
225
+ return self._hash(set())
226
+
227
+
228
+ class Function(TypeConstant):
229
+ def __init__(self, params: List, outputs: List):
230
+ self.params = params
231
+ self.outputs = outputs
232
+
233
+ @memoize
234
+ def __repr__(self, memo=None):
235
+ param_str = ", ".join(repr(param) for param in self.params)
236
+ outputs_str = ", ".join(repr(output) for output in self.outputs)
237
+ return f"func({param_str}) -> {outputs_str}"
168
238
 
169
239
  def __eq__(self, other):
170
- return type(other) is type(self) and self.fields == other.fields
240
+ if not isinstance(other, Function):
241
+ return False
242
+ return self.params == other.params and self.outputs == other.outputs
243
+
244
+ def _hash(self, visited: Set[int]):
245
+ if id(self) in visited:
246
+ return 0
247
+ visited.add(id(self))
248
+
249
+ params_hash = tuple(param._hash(visited) for param in self.params)
250
+ outputs_hash = tuple(out._hash(visited) for out in self.outputs)
251
+ return hash((Function, params_hash, outputs_hash))
171
252
 
172
253
  def __hash__(self):
173
- return hash((type(self), self._hash_fields()))
254
+ return self._hash(set())
174
255
 
175
256
 
176
257
  class TypeVariableReference(TypeConstant):
177
258
  def __init__(self, typevar):
178
259
  self.typevar = typevar
179
260
 
180
- def __repr__(self):
261
+ def __repr__(self, memo=None):
181
262
  return "ref(%s)" % self.typevar
182
263
 
183
264
  def __eq__(self, other):
@@ -1,16 +1,17 @@
1
+ # pylint:disable=bad-builtin
1
2
  from typing import List, Set, Optional, Dict, Union, TYPE_CHECKING
2
3
 
3
4
  from ...sim_type import SimStruct, SimTypePointer, SimTypeArray
4
5
  from ..analysis import Analysis, AnalysesHub
5
6
  from .simple_solver import SimpleSolver
6
7
  from .translator import TypeTranslator
7
- from .typeconsts import Struct, Pointer, TypeConstant, Array
8
- from .typevars import Equivalence
8
+ from .typeconsts import Struct, Pointer, TypeConstant, Array, TopType
9
+ from .typevars import Equivalence, Subtype, TypeVariable
9
10
 
10
11
  if TYPE_CHECKING:
11
12
  from angr.sim_variable import SimVariable
12
13
  from angr.sim_type import SimType
13
- from .typevars import TypeVariable, TypeConstraint
14
+ from .typevars import TypeConstraint
14
15
 
15
16
 
16
17
  class Typehoon(Analysis):
@@ -30,6 +31,7 @@ class Typehoon(Analysis):
30
31
  def __init__(
31
32
  self,
32
33
  constraints,
34
+ func_var,
33
35
  ground_truth=None,
34
36
  var_mapping: Optional[Dict["SimVariable", Set["TypeVariable"]]] = None,
35
37
  must_struct: Optional[Set["TypeVariable"]] = None,
@@ -43,9 +45,10 @@ class Typehoon(Analysis):
43
45
  :param must_struct:
44
46
  """
45
47
 
46
- self._constraints: Set["TypeConstraint"] = constraints
48
+ self.func_var: "TypeVariable" = func_var
49
+ self._constraints: Dict["TypeVariable", Set["TypeConstraint"]] = constraints
47
50
  self._ground_truth: Optional[Dict["TypeVariable", "SimType"]] = ground_truth
48
- self._var_mapping = var_mapping # variable mapping is only used for debugging purposes
51
+ self._var_mapping = var_mapping
49
52
  self._must_struct = must_struct
50
53
 
51
54
  self.bits = self.project.arch.bits
@@ -95,9 +98,11 @@ class Typehoon(Analysis):
95
98
  for tv in typevars:
96
99
  typevar_to_var[tv] = k
97
100
 
98
- print(f"### {len(self._constraints)} constraints")
99
- for constraint in self._constraints:
100
- print(" " + constraint.pp_str(typevar_to_var))
101
+ print(f"### {sum(map(len, self._constraints.values()))} constraints")
102
+ for func_var in self._constraints:
103
+ print(f"{func_var}:")
104
+ for constraint in self._constraints[func_var]:
105
+ print(" " + constraint.pp_str(typevar_to_var))
101
106
  print("### end of constraints ###")
102
107
 
103
108
  def pp_solution(self) -> None:
@@ -133,7 +138,7 @@ class Typehoon(Analysis):
133
138
  if self._ground_truth:
134
139
  translator = TypeTranslator(arch=self.project.arch)
135
140
  for tv, sim_type in self._ground_truth.items():
136
- self._constraints.add(Equivalence(tv, translator.simtype2tc(sim_type)))
141
+ self._constraints[self.func_var].add(Equivalence(tv, translator.simtype2tc(sim_type)))
137
142
 
138
143
  self._solve()
139
144
  self._specialize()
@@ -144,7 +149,19 @@ class Typehoon(Analysis):
144
149
  self.simtypes_solution.update(self._ground_truth)
145
150
 
146
151
  def _solve(self):
147
- solver = SimpleSolver(self.bits, self._constraints)
152
+ typevars = set()
153
+ if self._var_mapping:
154
+ for variable_typevars in self._var_mapping.values():
155
+ typevars |= variable_typevars
156
+ else:
157
+ # collect type variables from constraints
158
+ for constraint in self._constraints[self.func_var]:
159
+ if isinstance(constraint, Subtype):
160
+ if isinstance(constraint.sub_type, TypeVariable):
161
+ typevars.add(constraint.sub_type)
162
+ if isinstance(constraint.super_type, TypeVariable):
163
+ typevars.add(constraint.super_type)
164
+ solver = SimpleSolver(self.bits, self._constraints, typevars)
148
165
  self.solution = solver.solution
149
166
 
150
167
  def _specialize(self):
@@ -189,7 +206,10 @@ class Typehoon(Analysis):
189
206
  if all(off % alignment == 0 for off in offsets):
190
207
  # yeah!
191
208
  max_offset = offsets[-1]
192
- count = (max_offset + field0.size) // alignment
209
+ field0_size = 1
210
+ if not isinstance(field0, TopType):
211
+ field0_size = field0.size
212
+ count = (max_offset + field0_size) // alignment
193
213
  return Array(field0, count=count)
194
214
 
195
215
  return None
@@ -1,13 +1,19 @@
1
1
  # pylint:disable=missing-class-docstring
2
- from typing import Dict, Any, Optional, Set, TYPE_CHECKING
2
+ from typing import Dict, Any, Optional, Set, Iterable, Tuple, Union, TYPE_CHECKING
3
3
  from itertools import count
4
4
 
5
+ from angr.utils.constants import MAX_POINTSTO_BITS
6
+ from .variance import Variance
7
+
5
8
  if TYPE_CHECKING:
6
9
  from angr.sim_variable import SimVariable
10
+ from .typeconsts import TypeConstant
7
11
 
8
12
 
9
13
  # Type variables and constraints
10
14
 
15
+ TypeType = Union["TypeConstant", "TypeVariable", "DerivedTypeVariable"]
16
+
11
17
 
12
18
  class TypeConstraint:
13
19
  __slots__ = ()
@@ -79,7 +85,7 @@ class Subtype(TypeConstraint):
79
85
  "sub_type",
80
86
  )
81
87
 
82
- def __init__(self, sub_type, super_type):
88
+ def __init__(self, sub_type: TypeType, super_type: TypeType):
83
89
  self.super_type = super_type
84
90
  self.sub_type = sub_type
85
91
 
@@ -272,52 +278,103 @@ _typevariable_counter = count()
272
278
 
273
279
 
274
280
  class TypeVariable:
275
- __slots__ = ("idx",)
281
+ __slots__ = ("idx", "name")
276
282
 
277
- def __init__(self, idx: Optional[int] = None):
283
+ def __init__(self, idx: Optional[int] = None, name: Optional[str] = None):
278
284
  if idx is None:
279
285
  self.idx: int = next(_typevariable_counter)
280
286
  else:
281
287
  self.idx: int = idx
288
+ self.name = name
282
289
 
283
290
  def pp_str(self, mapping: Dict["TypeVariable", Any]) -> str:
284
- varname = mapping.get(self, None)
291
+ varname = mapping.get(self, self.name)
285
292
  if varname is None:
286
293
  return repr(self)
287
294
  return f"{varname} ({repr(self)})"
288
295
 
289
296
  def __eq__(self, other):
290
- return type(other) is TypeVariable and other.idx == self.idx
297
+ if type(other) is not TypeVariable:
298
+ return False
299
+ if self.name or other.name:
300
+ return self.name == other.name
301
+ return self.idx == other.idx
302
+
303
+ def _hash(self, visited=None): # pylint:disable=unused-argument
304
+ if self.name:
305
+ return hash((TypeVariable, self.name))
306
+ return hash((TypeVariable, self.idx))
291
307
 
292
308
  def __hash__(self):
293
- return hash((TypeVariable, self.idx))
309
+ return self._hash()
294
310
 
295
311
  def __repr__(self):
312
+ if self.name:
313
+ return f"{self.name}|tv_{self.idx:02d}"
296
314
  return "tv_%02d" % self.idx
297
315
 
298
316
 
299
317
  class DerivedTypeVariable(TypeVariable):
300
- __slots__ = (
301
- "type_var",
302
- "label",
303
- )
318
+ __slots__ = ("type_var", "labels")
319
+
320
+ type_var: Union[TypeVariable, "TypeConstant"]
304
321
 
305
- def __init__(self, type_var, label, idx=None):
322
+ def __init__(
323
+ self,
324
+ type_var: Optional[Union[TypeVariable, "DerivedTypeVariable"]],
325
+ label,
326
+ labels: Optional[Iterable["BaseLabel"]] = None,
327
+ idx=None,
328
+ ):
306
329
  super().__init__(idx=idx)
307
- self.type_var = type_var
308
- self.label = label
330
+ if isinstance(type_var, DerivedTypeVariable):
331
+ existing_labels = type_var.labels
332
+ self.type_var = type_var.type_var
333
+ assert not isinstance(self.type_var, DerivedTypeVariable)
334
+ else:
335
+ existing_labels = ()
336
+ self.type_var = type_var
337
+
338
+ if label is not None and labels:
339
+ raise TypeError("You cannot specify both label and labels at the same time")
340
+
341
+ if label is not None:
342
+ self.labels = existing_labels + (label,)
343
+ else:
344
+ self.labels: Tuple["BaseLabel"] = existing_labels + tuple(labels)
345
+
346
+ if not self.labels:
347
+ raise ValueError("A DerivedTypeVariable must have at least one label")
348
+
349
+ def one_label(self) -> Optional["BaseLabel"]:
350
+ return self.labels[0] if len(self.labels) == 1 else None
351
+
352
+ def path(self) -> Tuple["BaseLabel"]:
353
+ return self.labels
354
+
355
+ def longest_prefix(self) -> Optional[Union[TypeVariable, "DerivedTypeVariable"]]:
356
+ if not self.labels:
357
+ return None
358
+ if len(self.labels) == 1:
359
+ return self.type_var
360
+ return DerivedTypeVariable(self.type_var, None, labels=self.labels[:-1])
309
361
 
310
362
  def pp_str(self, mapping: Dict["TypeVariable", Any]) -> str:
311
- return f"{self.type_var.pp_str(mapping)}.{self.label}"
363
+ return ".".join([self.type_var.pp_str(mapping)] + [repr(lbl) for lbl in self.labels])
312
364
 
313
365
  def __eq__(self, other):
314
- return isinstance(other, DerivedTypeVariable) and self.type_var == other.type_var and self.label == other.label
366
+ return (
367
+ isinstance(other, DerivedTypeVariable) and self.type_var == other.type_var and self.labels == other.labels
368
+ )
369
+
370
+ def _hash(self, visited=None):
371
+ return hash((DerivedTypeVariable, self.type_var, self.labels))
315
372
 
316
373
  def __hash__(self):
317
- return hash((DerivedTypeVariable, self.type_var, self.label))
374
+ return self._hash()
318
375
 
319
376
  def __repr__(self):
320
- return f"{self.type_var!r}.{self.label!r}"
377
+ return ".".join([repr(self.type_var)] + [repr(lbl) for lbl in self.labels])
321
378
 
322
379
  def replace(self, replacements):
323
380
  typevar = None
@@ -332,7 +389,7 @@ class DerivedTypeVariable(TypeVariable):
332
389
 
333
390
  if typevar is not None:
334
391
  # replacement has happened
335
- return True, DerivedTypeVariable(typevar, self.label, idx=self.idx)
392
+ return True, DerivedTypeVariable(typevar, None, labels=self.labels, idx=self.idx)
336
393
  else:
337
394
  return False, self
338
395
 
@@ -397,7 +454,11 @@ class BaseLabel:
397
454
  return type(self) is type(other) and hash(self) == hash(other)
398
455
 
399
456
  def __hash__(self):
400
- return hash(tuple(getattr(self, k) for k in self.__slots__))
457
+ return hash((type(self),) + tuple(getattr(self, k) for k in self.__slots__))
458
+
459
+ @property
460
+ def variance(self) -> Variance:
461
+ return Variance.COVARIANT
401
462
 
402
463
 
403
464
  class FuncIn(BaseLabel):
@@ -433,6 +494,10 @@ class Store(BaseLabel):
433
494
  def __repr__(self):
434
495
  return "store"
435
496
 
497
+ @property
498
+ def variance(self) -> Variance:
499
+ return Variance.CONTRAVARIANT
500
+
436
501
 
437
502
  class AddN(BaseLabel):
438
503
  __slots__ = ("n",)
@@ -489,7 +554,9 @@ class HasField(BaseLabel):
489
554
  self.offset = offset
490
555
 
491
556
  def __repr__(self):
492
- return "<%d>@%d" % (self.bits, self.offset)
557
+ if self.bits == MAX_POINTSTO_BITS:
558
+ return f"<MAX_POINTSTO_BITS>@{self.offset}"
559
+ return f"<{self.bits} bits>@{self.offset}"
493
560
 
494
561
 
495
562
  class IsArray(BaseLabel):
@@ -0,0 +1,10 @@
1
+ import enum
2
+
3
+
4
+ class Variance(enum.Enum):
5
+ """
6
+ Enum class describing the variance of type constraints.
7
+ """
8
+
9
+ COVARIANT = 0
10
+ CONTRAVARIANT = 1