smallworld-re 1.0.0__py3-none-any.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.
Files changed (166) hide show
  1. smallworld/__init__.py +35 -0
  2. smallworld/analyses/__init__.py +14 -0
  3. smallworld/analyses/analysis.py +88 -0
  4. smallworld/analyses/code_coverage.py +31 -0
  5. smallworld/analyses/colorizer.py +682 -0
  6. smallworld/analyses/colorizer_summary.py +100 -0
  7. smallworld/analyses/field_detection/__init__.py +14 -0
  8. smallworld/analyses/field_detection/field_analysis.py +536 -0
  9. smallworld/analyses/field_detection/guards.py +26 -0
  10. smallworld/analyses/field_detection/hints.py +133 -0
  11. smallworld/analyses/field_detection/malloc.py +211 -0
  12. smallworld/analyses/forced_exec/__init__.py +3 -0
  13. smallworld/analyses/forced_exec/forced_exec.py +87 -0
  14. smallworld/analyses/underlays/__init__.py +4 -0
  15. smallworld/analyses/underlays/basic.py +13 -0
  16. smallworld/analyses/underlays/underlay.py +31 -0
  17. smallworld/analyses/unstable/__init__.py +4 -0
  18. smallworld/analyses/unstable/angr/__init__.py +0 -0
  19. smallworld/analyses/unstable/angr/base.py +12 -0
  20. smallworld/analyses/unstable/angr/divergence.py +274 -0
  21. smallworld/analyses/unstable/angr/model.py +383 -0
  22. smallworld/analyses/unstable/angr/nwbt.py +63 -0
  23. smallworld/analyses/unstable/angr/typedefs.py +170 -0
  24. smallworld/analyses/unstable/angr/utils.py +25 -0
  25. smallworld/analyses/unstable/angr/visitor.py +315 -0
  26. smallworld/analyses/unstable/angr_nwbt.py +106 -0
  27. smallworld/analyses/unstable/code_coverage.py +54 -0
  28. smallworld/analyses/unstable/code_reachable.py +44 -0
  29. smallworld/analyses/unstable/control_flow_tracer.py +71 -0
  30. smallworld/analyses/unstable/pointer_finder.py +90 -0
  31. smallworld/arch/__init__.py +0 -0
  32. smallworld/arch/aarch64_arch.py +286 -0
  33. smallworld/arch/amd64_arch.py +86 -0
  34. smallworld/arch/i386_arch.py +44 -0
  35. smallworld/emulators/__init__.py +14 -0
  36. smallworld/emulators/angr/__init__.py +7 -0
  37. smallworld/emulators/angr/angr.py +1652 -0
  38. smallworld/emulators/angr/default.py +15 -0
  39. smallworld/emulators/angr/exceptions.py +7 -0
  40. smallworld/emulators/angr/exploration/__init__.py +9 -0
  41. smallworld/emulators/angr/exploration/bounds.py +27 -0
  42. smallworld/emulators/angr/exploration/default.py +17 -0
  43. smallworld/emulators/angr/exploration/terminate.py +22 -0
  44. smallworld/emulators/angr/factory.py +55 -0
  45. smallworld/emulators/angr/machdefs/__init__.py +35 -0
  46. smallworld/emulators/angr/machdefs/aarch64.py +292 -0
  47. smallworld/emulators/angr/machdefs/amd64.py +192 -0
  48. smallworld/emulators/angr/machdefs/arm.py +387 -0
  49. smallworld/emulators/angr/machdefs/i386.py +221 -0
  50. smallworld/emulators/angr/machdefs/machdef.py +138 -0
  51. smallworld/emulators/angr/machdefs/mips.py +184 -0
  52. smallworld/emulators/angr/machdefs/mips64.py +189 -0
  53. smallworld/emulators/angr/machdefs/ppc.py +101 -0
  54. smallworld/emulators/angr/machdefs/riscv.py +261 -0
  55. smallworld/emulators/angr/machdefs/xtensa.py +255 -0
  56. smallworld/emulators/angr/memory/__init__.py +7 -0
  57. smallworld/emulators/angr/memory/default.py +10 -0
  58. smallworld/emulators/angr/memory/fixups.py +43 -0
  59. smallworld/emulators/angr/memory/memtrack.py +105 -0
  60. smallworld/emulators/angr/scratch.py +43 -0
  61. smallworld/emulators/angr/simos.py +53 -0
  62. smallworld/emulators/angr/utils.py +70 -0
  63. smallworld/emulators/emulator.py +1013 -0
  64. smallworld/emulators/hookable.py +252 -0
  65. smallworld/emulators/panda/__init__.py +5 -0
  66. smallworld/emulators/panda/machdefs/__init__.py +28 -0
  67. smallworld/emulators/panda/machdefs/aarch64.py +93 -0
  68. smallworld/emulators/panda/machdefs/amd64.py +71 -0
  69. smallworld/emulators/panda/machdefs/arm.py +89 -0
  70. smallworld/emulators/panda/machdefs/i386.py +36 -0
  71. smallworld/emulators/panda/machdefs/machdef.py +86 -0
  72. smallworld/emulators/panda/machdefs/mips.py +94 -0
  73. smallworld/emulators/panda/machdefs/mips64.py +91 -0
  74. smallworld/emulators/panda/machdefs/ppc.py +79 -0
  75. smallworld/emulators/panda/panda.py +575 -0
  76. smallworld/emulators/unicorn/__init__.py +13 -0
  77. smallworld/emulators/unicorn/machdefs/__init__.py +28 -0
  78. smallworld/emulators/unicorn/machdefs/aarch64.py +310 -0
  79. smallworld/emulators/unicorn/machdefs/amd64.py +326 -0
  80. smallworld/emulators/unicorn/machdefs/arm.py +321 -0
  81. smallworld/emulators/unicorn/machdefs/i386.py +137 -0
  82. smallworld/emulators/unicorn/machdefs/machdef.py +117 -0
  83. smallworld/emulators/unicorn/machdefs/mips.py +202 -0
  84. smallworld/emulators/unicorn/unicorn.py +684 -0
  85. smallworld/exceptions/__init__.py +5 -0
  86. smallworld/exceptions/exceptions.py +85 -0
  87. smallworld/exceptions/unstable/__init__.py +1 -0
  88. smallworld/exceptions/unstable/exceptions.py +25 -0
  89. smallworld/extern/__init__.py +4 -0
  90. smallworld/extern/ctypes.py +94 -0
  91. smallworld/extern/unstable/__init__.py +1 -0
  92. smallworld/extern/unstable/ghidra.py +129 -0
  93. smallworld/helpers.py +107 -0
  94. smallworld/hinting/__init__.py +8 -0
  95. smallworld/hinting/hinting.py +214 -0
  96. smallworld/hinting/hints.py +427 -0
  97. smallworld/hinting/unstable/__init__.py +2 -0
  98. smallworld/hinting/utils.py +19 -0
  99. smallworld/instructions/__init__.py +18 -0
  100. smallworld/instructions/aarch64.py +20 -0
  101. smallworld/instructions/arm.py +18 -0
  102. smallworld/instructions/bsid.py +67 -0
  103. smallworld/instructions/instructions.py +258 -0
  104. smallworld/instructions/mips.py +21 -0
  105. smallworld/instructions/x86.py +100 -0
  106. smallworld/logging.py +90 -0
  107. smallworld/platforms.py +95 -0
  108. smallworld/py.typed +0 -0
  109. smallworld/state/__init__.py +6 -0
  110. smallworld/state/cpus/__init__.py +32 -0
  111. smallworld/state/cpus/aarch64.py +563 -0
  112. smallworld/state/cpus/amd64.py +676 -0
  113. smallworld/state/cpus/arm.py +630 -0
  114. smallworld/state/cpus/cpu.py +71 -0
  115. smallworld/state/cpus/i386.py +239 -0
  116. smallworld/state/cpus/mips.py +374 -0
  117. smallworld/state/cpus/mips64.py +372 -0
  118. smallworld/state/cpus/powerpc.py +229 -0
  119. smallworld/state/cpus/riscv.py +357 -0
  120. smallworld/state/cpus/xtensa.py +80 -0
  121. smallworld/state/memory/__init__.py +7 -0
  122. smallworld/state/memory/code.py +70 -0
  123. smallworld/state/memory/elf/__init__.py +3 -0
  124. smallworld/state/memory/elf/elf.py +564 -0
  125. smallworld/state/memory/elf/rela/__init__.py +32 -0
  126. smallworld/state/memory/elf/rela/aarch64.py +27 -0
  127. smallworld/state/memory/elf/rela/amd64.py +32 -0
  128. smallworld/state/memory/elf/rela/arm.py +51 -0
  129. smallworld/state/memory/elf/rela/i386.py +32 -0
  130. smallworld/state/memory/elf/rela/mips.py +45 -0
  131. smallworld/state/memory/elf/rela/ppc.py +45 -0
  132. smallworld/state/memory/elf/rela/rela.py +63 -0
  133. smallworld/state/memory/elf/rela/riscv64.py +27 -0
  134. smallworld/state/memory/elf/rela/xtensa.py +15 -0
  135. smallworld/state/memory/elf/structs.py +55 -0
  136. smallworld/state/memory/heap.py +85 -0
  137. smallworld/state/memory/memory.py +181 -0
  138. smallworld/state/memory/stack/__init__.py +31 -0
  139. smallworld/state/memory/stack/aarch64.py +22 -0
  140. smallworld/state/memory/stack/amd64.py +42 -0
  141. smallworld/state/memory/stack/arm.py +66 -0
  142. smallworld/state/memory/stack/i386.py +22 -0
  143. smallworld/state/memory/stack/mips.py +34 -0
  144. smallworld/state/memory/stack/mips64.py +34 -0
  145. smallworld/state/memory/stack/ppc.py +34 -0
  146. smallworld/state/memory/stack/riscv.py +22 -0
  147. smallworld/state/memory/stack/stack.py +127 -0
  148. smallworld/state/memory/stack/xtensa.py +34 -0
  149. smallworld/state/models/__init__.py +6 -0
  150. smallworld/state/models/mmio.py +186 -0
  151. smallworld/state/models/model.py +163 -0
  152. smallworld/state/models/posix.py +455 -0
  153. smallworld/state/models/x86/__init__.py +2 -0
  154. smallworld/state/models/x86/microsoftcdecl.py +35 -0
  155. smallworld/state/models/x86/systemv.py +240 -0
  156. smallworld/state/state.py +962 -0
  157. smallworld/state/unstable/__init__.py +0 -0
  158. smallworld/state/unstable/elf.py +393 -0
  159. smallworld/state/x86_registers.py +30 -0
  160. smallworld/utils.py +935 -0
  161. smallworld_re-1.0.0.dist-info/LICENSE.txt +21 -0
  162. smallworld_re-1.0.0.dist-info/METADATA +189 -0
  163. smallworld_re-1.0.0.dist-info/RECORD +166 -0
  164. smallworld_re-1.0.0.dist-info/WHEEL +5 -0
  165. smallworld_re-1.0.0.dist-info/entry_points.txt +2 -0
  166. smallworld_re-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,261 @@
1
+ import typing
2
+
3
+ import angr
4
+ import archinfo
5
+
6
+ from ....platforms import Architecture, Byteorder
7
+ from .machdef import AngrMachineDef
8
+
9
+ # angr has no default calling convention for RISCV64
10
+ # Let's fix that.
11
+
12
+
13
+ class SimCCRISCV64(angr.calling_conventions.SimCC):
14
+ ARG_REGS = ["a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7"]
15
+ FP_ARG_REGS = ["fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7"]
16
+ RETURN_VAL = angr.calling_conventions.SimRegArg("a0", 8)
17
+ RETURN_ADDR = angr.calling_conventions.SimRegArg("ra", 8)
18
+ # angr doesn't type this field correctly
19
+ ARCH = archinfo.ArchRISCV64 # type: ignore[assignment]
20
+
21
+
22
+ angr.calling_conventions.register_default_cc("RISCV64", SimCCRISCV64)
23
+
24
+ # angr ALSO has no default syscall calling convention for RISCV64
25
+ # Let's fix that
26
+
27
+
28
+ class SimCCRISCV64LinuxSyscall(angr.calling_conventions.SimCCSyscall):
29
+ # Since the RISCV peeps don't seem to have written their kernel ABI,
30
+ # I RE'd the syscall convention from glibc.
31
+ # It looks like they use the same arg and return regs,
32
+ # except that they repurpose a7 as the syscall number.
33
+ ARG_REGS = ["a0", "a1", "a2", "a3", "a4", "a5", "a6"]
34
+ FP_ARG_REGS: typing.List[str] = []
35
+ RETURN_VAL = angr.calling_conventions.SimRegArg("a0", 8)
36
+ RETURN_ADDR = angr.calling_conventions.SimRegArg("ip_at_syscall", 4)
37
+ # angr doesn't type this field correctly
38
+ ARCH = archinfo.ArchRISCV64 # type: ignore[assignment]
39
+
40
+ @classmethod
41
+ def _match(cls, arch, args, sp_data):
42
+ # Never match; only occurs durring syscalls
43
+ return False
44
+
45
+ @staticmethod
46
+ def syscall_num(state):
47
+ return state.regs.a7
48
+
49
+
50
+ angr.calling_conventions.register_syscall_cc(
51
+ "RISCV64", "default", SimCCRISCV64LinuxSyscall
52
+ )
53
+
54
+
55
+ class RISCV64MachineDef(AngrMachineDef):
56
+ arch = Architecture.RISCV64
57
+ byteorder = Byteorder.LITTLE
58
+
59
+ angr_arch = archinfo.ArchRISCV64()
60
+
61
+ pc_reg = "pc"
62
+
63
+ _registers = {
64
+ # *** General-Purpose Registers ***
65
+ # x0 is wired to 0, and aliased as "zero"
66
+ "x0": "x0",
67
+ "zero": "zero",
68
+ # x1 acts as the link register
69
+ # NOTE: ra is the official name; lr might be an angr invention.
70
+ "x1": "x1",
71
+ "ra": "ra",
72
+ # x2 acts as the stack pointer
73
+ "x2": "x2",
74
+ "sp": "sp",
75
+ # x3 acts as the global pointer
76
+ "x3": "x3",
77
+ "gp": "gp",
78
+ # x4 acts as the thread pointer
79
+ "x4": "x4",
80
+ "tp": "tp",
81
+ # x5 is a temporary register
82
+ "x5": "x5",
83
+ "t0": "t0",
84
+ # x6 is a temporary register
85
+ "x6": "x6",
86
+ "t1": "t1",
87
+ # x7 is a temporary register
88
+ "x7": "x7",
89
+ "t2": "t2",
90
+ # x8 is a callee-saved register
91
+ "x8": "x8",
92
+ "s0": "s0",
93
+ # x9 is a callee-saved register
94
+ "x9": "x9",
95
+ "s1": "s1",
96
+ # x10 is argument 0
97
+ "x10": "x10",
98
+ "a0": "a0",
99
+ # x11 is argument 1
100
+ "x11": "x11",
101
+ "a1": "a1",
102
+ # x12 is argument 2
103
+ "x12": "x12",
104
+ "a2": "a2",
105
+ # x13 is argument 3
106
+ "x13": "x13",
107
+ "a3": "a3",
108
+ # x14 is argument 4
109
+ "x14": "x14",
110
+ "a4": "a4",
111
+ # x15 is argument 5
112
+ "x15": "x15",
113
+ "a5": "a5",
114
+ # x16 is argument 6
115
+ "x16": "x16",
116
+ "a6": "a6",
117
+ # x17 is argument 7
118
+ "x17": "x17",
119
+ "a7": "a7",
120
+ # x18 is a callee-saved register
121
+ "x18": "x18",
122
+ "s2": "s2",
123
+ # x19 is a callee-saved register
124
+ "x19": "x19",
125
+ "s3": "s3",
126
+ # x20 is a callee-saved register
127
+ "x20": "x20",
128
+ "s4": "s4",
129
+ # x21 is a callee-saved register
130
+ "x21": "x21",
131
+ "s5": "s5",
132
+ # x22 is a callee-saved register
133
+ "x22": "x22",
134
+ "s6": "s6",
135
+ # x23 is a callee-saved register
136
+ "x23": "x23",
137
+ "s7": "s7",
138
+ # x24 is a callee-saved register
139
+ "x24": "x24",
140
+ "s8": "s8",
141
+ # x25 is a callee-saved register
142
+ "x25": "x25",
143
+ "s9": "s9",
144
+ # x26 is a callee-saved register
145
+ "x26": "x26",
146
+ "s10": "s10",
147
+ # x27 is a callee-saved register
148
+ "x27": "x27",
149
+ "s11": "s11",
150
+ # x28 is a temporary register
151
+ "x28": "x28",
152
+ "t3": "t3",
153
+ # x29 is a temporary register
154
+ "x29": "x29",
155
+ "t4": "t4",
156
+ # x30 is a temporary register
157
+ "x30": "x30",
158
+ "t5": "t5",
159
+ # x31 is a temporary register
160
+ "x31": "x31",
161
+ "t6": "t6",
162
+ # *** Program Counter ***
163
+ "pc": "pc",
164
+ # *** Floating-Point Registers ***
165
+ # f0 is a temporary register
166
+ "f0": "f0",
167
+ "ft0": "ft0",
168
+ # f1 is a temporary register
169
+ "f1": "f1",
170
+ "ft1": "ft1",
171
+ # f2 is a temporary register
172
+ "f2": "f2",
173
+ "ft2": "ft2",
174
+ # f3 is a temporary register
175
+ "f3": "f3",
176
+ "ft3": "ft3",
177
+ # f4 is a temporary register
178
+ "f4": "f4",
179
+ "ft4": "ft4",
180
+ # f5 is a temporary register
181
+ "f5": "f5",
182
+ "ft5": "ft5",
183
+ # f6 is a temporary register
184
+ "f6": "f6",
185
+ "ft6": "ft6",
186
+ # f7 is a temporary register
187
+ "f7": "f7",
188
+ "ft7": "ft7",
189
+ # f8 is a callee saved register
190
+ "f8": "f8",
191
+ "fs0": "fs0",
192
+ # f9 is a callee saved register
193
+ "f9": "f9",
194
+ "fs1": "fs1",
195
+ # f10 is argument 0
196
+ "f10": "f10",
197
+ "a0": "a0",
198
+ # f11 is argument 1
199
+ "f11": "f11",
200
+ "a1": "a1",
201
+ # f12 is argument 2
202
+ "f12": "f12",
203
+ "a2": "a2",
204
+ # f13 is argument 3
205
+ "f13": "f13",
206
+ "a3": "a3",
207
+ # f14 is argument 4
208
+ "f14": "f14",
209
+ "a4": "a4",
210
+ # f15 is argument 5
211
+ "f15": "f15",
212
+ "a5": "a5",
213
+ # f16 is argument 6
214
+ "f16": "f16",
215
+ "a6": "a6",
216
+ # f7 is argument 7
217
+ "f17": "f17",
218
+ "a7": "a7",
219
+ # f18 is a callee-saved register
220
+ "f18": "f18",
221
+ "fs2": "fs2",
222
+ # f19 is a callee-saved register
223
+ "f19": "f19",
224
+ "fs3": "fs3",
225
+ # f20 is a callee-saved register
226
+ "f20": "f20",
227
+ "fs4": "fs4",
228
+ # f21 is a callee-saved register
229
+ "f21": "f21",
230
+ "fs5": "fs5",
231
+ # f22 is a callee-saved register
232
+ "f22": "f22",
233
+ "fs6": "fs6",
234
+ # f23 is a callee-saved register
235
+ "f23": "f23",
236
+ "fs7": "fs7",
237
+ # f24 is a callee-saved register
238
+ "f24": "f24",
239
+ "fs8": "fs8",
240
+ # f25 is a callee-saved register
241
+ "f25": "f25",
242
+ "fs9": "fs9",
243
+ # f26 is a callee-saved register
244
+ "f26": "f26",
245
+ "fs10": "fs10",
246
+ # f27 is a callee-saved register
247
+ "f27": "f27",
248
+ "fs11": "fs11",
249
+ # f28 is a temporary register
250
+ "f28": "f28",
251
+ "ft8": "ft8",
252
+ # f29 is a temporary register
253
+ "f29": "f29",
254
+ "ft9": "ft9",
255
+ # f30 is a temporary register
256
+ "f30": "f30",
257
+ "ft10": "ft10",
258
+ # f31 is a temporary register
259
+ "f31": "f31",
260
+ "ft11": "ft11",
261
+ }
@@ -0,0 +1,255 @@
1
+ import enum
2
+ import typing
3
+
4
+ import angr
5
+ import pypcode
6
+
7
+ from ....exceptions import EmulationError
8
+ from ....platforms import Architecture, Byteorder
9
+ from .machdef import PcodeMachineDef
10
+
11
+
12
+ def handle_nop(irsb, i):
13
+ # This op has no impact on user-facing machine state.
14
+ irsb._ops.pop(i)
15
+ return i
16
+
17
+
18
+ def handle_sigtrap(irsb, i):
19
+ # This op should terminate this block with SIGTRAP
20
+ next_addr = irsb._ops[i - 1].inputs[0].offset + 3
21
+ irsb._ops = irsb._ops[0:i]
22
+ irsb.next = next_addr
23
+ irsb._size = next_addr - irsb.addr
24
+ irsb._instruction_addresses = list(
25
+ filter(lambda x: x < next_addr, irsb._instruction_addresses)
26
+ )
27
+ irsb.jumpkind = "Ijk_SigTRAP"
28
+ return i
29
+
30
+
31
+ def handle_sigill(irsb, i):
32
+ # This op should terminate this block with SIGILL
33
+ next_addr = irsb._ops[i - 1].inputs[0].offset + 3
34
+ irsb._ops = irsb._ops[0:i]
35
+ irsb.next = next_addr
36
+ irsb._size = next_addr - irsb.addr
37
+ irsb._instruction_addresses = list(
38
+ filter(lambda x: x < next_addr, irsb._instruction_addresses)
39
+ )
40
+ irsb.jumpkind = "Ijk_SigILL"
41
+ return i
42
+
43
+
44
+ def handle_syscall(irsb, i):
45
+ # This op should terminate this block with a syscall
46
+ next_addr = irsb._ops[i - 1].inputs[0].offset + 3
47
+ irsb._ops = irsb._ops[0:i]
48
+ irsb.next = next_addr
49
+ irsb._size = next_addr - irsb.addr
50
+ irsb._instruction_addresses = list(
51
+ filter(lambda x: x < next_addr, irsb._instruction_addresses)
52
+ )
53
+ irsb.jumpkind = "Ijk_Sys_syscall"
54
+
55
+ return i
56
+
57
+
58
+ def handle_nope(irsb, i):
59
+ # This op cannot be handled by angr
60
+ userop = XtensaUserOp(irsb._ops[i].inputs[0].offset)
61
+ raise EmulationError(f"Unhandled user op {userop!r}")
62
+
63
+
64
+ def handle_unimpl(irsb, i):
65
+ # I don't know what this op does yet
66
+ userop = XtensaUserOp(irsb._ops[i].inputs[0].offset)
67
+ raise EmulationError(f"Unimplemented user op {userop!r}")
68
+
69
+
70
+ class UpdatedEnumMeta(enum.EnumMeta):
71
+ def __contains__(cls, obj):
72
+ if isinstance(obj, int):
73
+ return obj in cls._value2member_map_
74
+ return enum.EnumMeta.__contains__(enum.EnumMeta, obj)
75
+
76
+
77
+ class XtensaUserOp(enum.IntEnum, metaclass=UpdatedEnumMeta):
78
+ def __new__(
79
+ cls, val: int, name: str = "", handler: typing.Any = None, desc: str = ""
80
+ ):
81
+ obj = int.__new__(cls, val)
82
+ obj._value_ = val
83
+ obj.short_name = name
84
+ obj.handler = handler
85
+ obj.description = desc
86
+ return obj
87
+
88
+ def __init__(
89
+ self, val: int, name: str = "", handler: typing.Any = None, desc: str = ""
90
+ ):
91
+ self._value_: int = val
92
+ self.short_name: str = name
93
+ self.handler: typing.Any = handler
94
+ self.description: str = desc
95
+
96
+ def __repr__(self):
97
+ return f"{hex(self.value)}: {self.short_name} - {self.description}"
98
+
99
+ BREAKPOINT = 0x00, "breakpoint", handle_sigtrap, "Breakpoint Instruction"
100
+ DHI = 0x01, "dhi", handle_nop, "Data Cache Hit Invalidate"
101
+ DHU = 0x02, "dhu", handle_nop, "Data Cache Hit Unlock"
102
+ DHWB = 0x03, "dhwb", handle_nop, "Data Cache Hit Writeback"
103
+ DHWBI = 0x04, "dhwbi", handle_nop, "Data Cache Hit Writeback Invalidate"
104
+ DII = 0x05, "dii", handle_nop, "Data Cache Index Invalidate"
105
+ DIU = 0x06, "diu", handle_nop, "Data Cache Index Unlock"
106
+ DIWB = 0x07, "diwb", handle_nop, "Data Cache Index Writeback"
107
+ DIWBI = 0x08, "diwbi", handle_nop, "Data Cache Index Writeback Invalidate"
108
+ DPFL = 0x09, "dpfl", handle_nop, "Data Cache Prefetch And Lock"
109
+ DPFR = 0x0A, "dpfr", handle_nop, "Data Cache Prefetch For Read"
110
+ DPFRO = 0x0B, "dpfro", handle_nop, "Data Cache Prefetch For Read Once"
111
+ DPFW = 0x0C, "dpfw", handle_nop, "Data Cache Prefetch For Write"
112
+ DPFWO = 0x0D, "dpfwo", handle_nop, "Data Cache Prefetch For Write Once"
113
+ DSYNC = 0x0E, "dsync", handle_nop, "Load/Store Synchronize"
114
+ ESYNC = 0x0F, "esync", handle_nop, "Execute Synchronize"
115
+ EXCW = 0x10, "excw", handle_sigtrap, "Exception Wait"
116
+ EXTW = 0x11, "extw", handle_sigtrap, "External Wait"
117
+ IDTLB = 0x12, "idtlb", handle_nop, "Invalidate Data TLB Entry"
118
+ IHI = 0x13, "ihi", handle_nop, "Instruction Cache Hit Invalidate"
119
+ IHU = 0x14, "ihu", handle_nop, "Instruction Cache Hit Unlock"
120
+ III = 0x15, "iii", handle_nop, "Instruction Cache Index Invalidate"
121
+ IITLB = 0x16, "iitlb", handle_nop, "Invalidate Instruction TLB Entry"
122
+ IIU = 0x17, "iiu", handle_nop, "Instruction Cache Index Unlock"
123
+ ILL = 0x18, "ill", handle_sigill, "Illegal Instruction"
124
+ IPF = 0x19, "ipf", handle_nop, "Instruction Cache Prefetch"
125
+ IPFL = 0x1A, "ipfl", handle_nop, "Instruction Cache Prefetch And Lock"
126
+ ISYNC = 0x1B, "isync", handle_nop, "Instruction Fetch Synchronize"
127
+ ACQUIRE = 0x1C, "acquire", handle_unimpl, "???"
128
+ LDCT = 0x1D, "ldct", handle_nope, "Load Data Cache Tag"
129
+ LICT = 0x1E, "lict", handle_nope, "Load Instruction Cache Tag"
130
+ LICW = 0x1F, "licw", handle_nope, "Load Instruction Cache Word"
131
+ MEMW = 0x20, "memw", handle_sigtrap, "Memory Wait"
132
+ NSA = 0x21, "nsa", handle_unimpl, "Normalization Shift Amount"
133
+ NSAU = 0x22, "nsau", handle_unimpl, "Normalization Shift Amount Unsigned"
134
+ PDTLB = 0x23, "pdtlb", handle_nope, "Probe Data TLB"
135
+ PITLB = 0x24, "pitlb", handle_nope, "Probe Instruction TLB"
136
+ RDTLB0 = 0x25, "rdtlb0", handle_nope, "Read Data TLB Entry Virtual"
137
+ RDTLB1 = 0x26, "rdtlb1", handle_nope, "Read Data TLB Entry Translation"
138
+ RER = 0x27, "rer", handle_nope, "Read External Register"
139
+ RESTORE4 = 0x28, "restore4", handle_unimpl, "???"
140
+ RESTORE8 = 0x29, "restore8", handle_unimpl, "???"
141
+ RESTORE12 = 0x2A, "restore12", handle_unimpl, "???"
142
+ RFDD = 0x2B, "rfdd", handle_nope, "Return from Debug and Dispatch"
143
+ RFDE = 0x2C, "rfde", handle_nope, "Return from Double Exception"
144
+ RFDO = 0x2D, "rfdo", handle_nope, "Return from Debug Operation"
145
+ RFE = 0x2E, "rfe", handle_nope, "Return from Exception"
146
+ RFI = 0x2F, "rfi", handle_nope, "Return from Interrupt"
147
+ RFME = 0x30, "rfme", handle_nope, "Return from Memory Error"
148
+ RFUE = 0x31, "rfue", handle_nope, "Return from User Exception"
149
+ RFWO = 0x32, "rfwo", handle_nope, "Return from Window Overflow"
150
+ RFWU = 0x33, "rfwu", handle_nope, "Return from Window Underflow"
151
+ RITLB0 = 0x34, "ritlb0", handle_nope, "Read Instruction TLB Entry Virtual"
152
+ RITLB1 = 0x35, "ritlb1", handle_nope, "Read Instruction TLB Entry Translation"
153
+ RSIL = 0x36, "rsil", handle_nope, "Read and Set Interrupt Level"
154
+ RSR = 0x37, "rsr", handle_unimpl, "Read Special Register"
155
+ RSYNC = 0x38, "rsync", handle_nop, "Register Read Synchronize"
156
+ RUR = 0x39, "rur", handle_unimpl, "Read User Register"
157
+ S32C1I = 0x3A, "s32c1i", handle_unimpl, "Store 32-bit compare conditional"
158
+ RELEASE = 0x3B, "release", handle_unimpl, "???"
159
+ RESTOREREGWINDOW = 0x3C, "restoreregwindow", handle_unimpl, "???"
160
+ ROTATEREGWINDOW = 0x3D, "rotateregwindow", handle_unimpl, "???"
161
+ SDCT = 0x3E, "sdct", handle_nope, "Store Data Cache Tag"
162
+ SICT = 0x3F, "sict", handle_nope, "Store Instruction Cache Tag"
163
+ SICW = 0x40, "sicw", handle_nope, "Store Instruction Cache Word"
164
+ SIMCALL = 0x41, "simcall", handle_nop, "Simulator Call"
165
+ SYSCALL = 0x42, "syscall", handle_syscall, "System Call"
166
+ SWAP4 = 0x43, "swap4", handle_unimpl, "???"
167
+ SWAP8 = 0x44, "swap8", handle_unimpl, "???"
168
+ SWAP12 = 0x45, "swap12", handle_unimpl, "???"
169
+ WAITI = 0x46, "waiti", handle_sigtrap, "Wait for Interrupt"
170
+ WDTLB = 0x47, "wdtlb", handle_nop, "Write Data TLB Entry"
171
+ WER = 0x48, "wer", handle_nop, "Write External Register"
172
+ WITLB = 0x49, "witlb", handle_nop, "Write Instruction TLB Entry"
173
+ WSR = 0x4A, "wsr", handle_unimpl, "Write Special Register"
174
+ WUR = 0x4B, "wur", handle_unimpl, "Write User Register"
175
+ XSR = 0x4C, "xsr", handle_unimpl, "Exchange Special Register"
176
+
177
+
178
+ # Angr doesn't have a syscall calling convention for xtensa.
179
+ # Remedy that situation.
180
+ class SimCCXtensaLinuxSyscall(angr.calling_conventions.SimCCSyscall):
181
+ ARG_REGS = ["a6", "a3", "a4", "a5", "a8", "a9"]
182
+ FP_ARG_REGS: typing.List[str] = []
183
+ RETURN_VAL = angr.calling_conventions.SimRegArg("a2", 4)
184
+ RETURN_ADDR = angr.calling_conventions.SimRegArg("ip_at_syscall", 4)
185
+ ARCH = None
186
+
187
+ @classmethod
188
+ def _match(cls, arch, args, sp_data):
189
+ # Never match; only occurs durring syscalls
190
+ return False
191
+
192
+ @staticmethod
193
+ def syscall_num(state):
194
+ return state.regs.a2
195
+
196
+
197
+ angr.calling_conventions.register_syscall_cc(
198
+ "Xtensa:LE:32:default", "default", SimCCXtensaLinuxSyscall
199
+ )
200
+
201
+
202
+ class XTensaMachineDef(PcodeMachineDef):
203
+ arch = Architecture.XTENSA
204
+ _registers = {f"a{i}": f"a{i}" for i in range(0, 16)} | {"pc": "pc", "sar": "sar"}
205
+ pc_reg = "pc"
206
+
207
+ def successors(self, state: angr.SimState, **kwargs) -> typing.Any:
208
+ # xtensa includes a _LOT_ of custom pcode operations.
209
+
210
+ # Fetch or compute the IR block for our state
211
+ if "irsb" in kwargs and kwargs["irsb"] is not None:
212
+ # Someone's already specified an IR block.
213
+ irsb = kwargs["irsb"]
214
+ else:
215
+ # Disable optimization; it doesn't work
216
+ kwargs["opt_level"] = 0
217
+
218
+ # Compute the block from the state.
219
+ # Pray to the Powers that kwargs are compatible.
220
+ irsb = state.block(**kwargs).vex
221
+
222
+ i = 0
223
+ while i < len(irsb._ops):
224
+ op = irsb._ops[i]
225
+ if op.opcode == pypcode.OpCode.CALLOTHER:
226
+ # This is a user-defined Pcode op.
227
+ # Alter irsb to mimic its behavior, if we can.
228
+ opnum = op.inputs[0].offset
229
+
230
+ if opnum not in XtensaUserOp:
231
+ # Not a userop.
232
+ raise EmulationError(f"Undefined user op {hex(opnum)}")
233
+ # get the enum struct
234
+ userop = XtensaUserOp(opnum)
235
+
236
+ # Invoke the handler
237
+ i = userop.handler(irsb, i)
238
+ else:
239
+ i += 1
240
+
241
+ # Force the engine to use our IR block
242
+ kwargs["irsb"] = irsb
243
+
244
+ # Turn the crank on the engine
245
+ return super().successors(state, **kwargs)
246
+
247
+
248
+ class XTensaELMachineDef(XTensaMachineDef):
249
+ byteorder = Byteorder.LITTLE
250
+ pcode_language = "Xtensa:LE:32:default"
251
+
252
+
253
+ class XTensaBEMachineDef(XTensaMachineDef):
254
+ byteorder = Byteorder.BIG
255
+ pcode_language = "Xtensa:BE:32:default"
@@ -0,0 +1,7 @@
1
+ from .default import DefaultMemoryPlugin
2
+ from .memtrack import TrackerMemoryMixin
3
+
4
+ __all__ = [
5
+ "DefaultMemoryPlugin",
6
+ "TrackerMemoryMixin",
7
+ ]
@@ -0,0 +1,10 @@
1
+ import angr
2
+
3
+ from .fixups import FixupMemoryMixin
4
+ from .memtrack import TrackerMemoryMixin
5
+
6
+
7
+ class DefaultMemoryPlugin( # type: ignore[misc]
8
+ TrackerMemoryMixin, FixupMemoryMixin, angr.storage.DefaultMemory
9
+ ):
10
+ pass
@@ -0,0 +1,43 @@
1
+ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
2
+
3
+
4
+ class FixupMemoryMixin(MemoryMixin):
5
+ """Mixin providing some basic bug-fixed/feature improvements
6
+
7
+ angr doesn't always behave as I'd expect.
8
+ This mixin helps things a little.
9
+ """
10
+
11
+ def _concretize_addr(self, supercall, addr, strategies=None, condition=None):
12
+ # Handle potential errors durring concretization
13
+ # This works the same for reads and writes, so why duplicate code?
14
+
15
+ if not self.state.solver.satisfiable():
16
+ # This state isn't satisfiable; concretization is impossible, but irrelevant.
17
+ #
18
+ # Under some conditions of which I'm uncertain,
19
+ # the concretizer will try to run even if the state is already unsat.
20
+ # Since the concretizer relies on the solver,
21
+ # it fails with a big ole' fatal exception.
22
+ #
23
+ # The successor computation will eventually kill these states anyway,
24
+ # so just return a dummy value to keep things running.
25
+ return [0xDEAD0000]
26
+
27
+ return supercall(addr, strategies=strategies, condition=condition)
28
+
29
+ def concretize_read_addr(self, addr, strategies=None, condition=None):
30
+ return self._concretize_addr(
31
+ super().concretize_read_addr,
32
+ addr,
33
+ strategies=strategies,
34
+ condition=condition,
35
+ )
36
+
37
+ def concretize_write_addr(self, addr, strategies=None, condition=None):
38
+ return self._concretize_addr(
39
+ super().concretize_write_addr,
40
+ addr,
41
+ strategies=strategies,
42
+ condition=condition,
43
+ )
@@ -0,0 +1,105 @@
1
+ import logging
2
+
3
+ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
4
+
5
+ from ..utils import reg_name_from_offset
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ class TrackerMemoryMixin(MemoryMixin):
11
+ """Memory mixin for tracking used data.
12
+
13
+ Printing every AMD64 register is a pain,
14
+ and finding used memory in angr is a pain.
15
+ This tracks which parts of memory are in use,
16
+ mostly to avoid overprinting.
17
+
18
+ NOTE: This class needs to go in a pretty specific place in a memory mixin hierarchy.
19
+
20
+ It needs to go above anything that overrides _default_value(),
21
+ or else it will pick up defaulting addresses before they are defined,
22
+ possibly resulting in recursive calls if you try to use pp().
23
+
24
+ Conversely, it should go below anything that alters
25
+ what is actually getting passed to the default memory mixins,
26
+ such as changes to address concretization.
27
+ """
28
+
29
+ def __init__(self, **kwargs):
30
+ super().__init__(**kwargs)
31
+ self.dirty = dict()
32
+ self.dirty_addrs = set()
33
+
34
+ @MemoryMixin.memo
35
+ def copy(self, memo):
36
+ o = super().copy(memo)
37
+ o.dirty = dict()
38
+ o.dirty.update(self.dirty)
39
+ o.dirty_addrs = set()
40
+ o.dirty_addrs.update(self.dirty_addrs)
41
+ return o
42
+
43
+ def _track_memory(self, addr, size):
44
+ """Mark a memory range as 'in-use'"""
45
+ # TODO: Make this more efficient
46
+ # Detecting overlapping ranges is a pain.
47
+ # This implementation is easy, but its memory usage
48
+ # and runtime cost will explode violently
49
+ # if large amounts of memory are in use.
50
+ track = False
51
+ for i in range(0, size):
52
+ if not track and addr + i not in self.dirty_addrs:
53
+ track = True
54
+ self.dirty[addr] = size
55
+ self.dirty_addrs.add(addr + i)
56
+ if track:
57
+ log.debug(f"Tracking {addr:x}, {size}")
58
+
59
+ def _default_value(self, addr, size, **kwargs):
60
+ out = super()._default_value(addr, size, **kwargs)
61
+ self._track_memory(addr, size)
62
+ return out
63
+
64
+ def _store_one_addr(
65
+ self, concrete_addr, data, trivial, addr, condition, size, **kwargs
66
+ ):
67
+ out = super()._store_one_addr(
68
+ concrete_addr, data, trivial, addr, condition, size, **kwargs
69
+ )
70
+ self._track_memory(concrete_addr, size)
71
+ return out
72
+
73
+ def pp(self, log):
74
+ addrs = list(self.dirty.keys())
75
+ addrs.sort()
76
+ for addr in addrs:
77
+ code = False
78
+ size = self.dirty[addr]
79
+ if self.id == "reg":
80
+ name = reg_name_from_offset(self.state.arch, addr, size)
81
+ else:
82
+ name = f"0x{addr:x}"
83
+ if code:
84
+ log(f"\t{name}: <code [{hex(size)} bytes]>")
85
+ else:
86
+ val = self.load(addr, size, disable_actions=True)
87
+ log(f"\t{name}: {val}")
88
+
89
+ def create_hint(self):
90
+ if self.id == "reg":
91
+ return {
92
+ reg_name_from_offset(self.state.arch, addr, self.dirty[addr]): str(
93
+ self.load(addr, self.dirty[addr], disable_actions=True)
94
+ )
95
+ for addr in list(self.dirty.keys())
96
+ }
97
+ else:
98
+ return {
99
+ addr: str(
100
+ self.load(
101
+ addr, self.dirty[addr], disable_actions=True, inspect=False
102
+ )
103
+ )
104
+ for addr in list(self.dirty.keys())
105
+ }