smallworld-re 1.0.3__py3-none-any.whl → 2.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 (306) hide show
  1. smallworld/analyses/__init__.py +8 -0
  2. smallworld/analyses/analysis.py +8 -67
  3. smallworld/analyses/code_coverage.py +1 -2
  4. smallworld/analyses/colorizer.py +301 -534
  5. smallworld/analyses/colorizer_def_use.py +217 -0
  6. smallworld/analyses/colorizer_summary.py +173 -83
  7. smallworld/analyses/field_detection/field_analysis.py +7 -8
  8. smallworld/analyses/field_detection/hints.py +1 -1
  9. smallworld/analyses/field_detection/malloc.py +2 -2
  10. smallworld/analyses/trace_execution.py +160 -0
  11. smallworld/analyses/trace_execution_types.py +42 -0
  12. smallworld/analyses/unstable/angr/divergence.py +1 -2
  13. smallworld/analyses/unstable/angr/model.py +5 -6
  14. smallworld/analyses/unstable/angr_nwbt.py +3 -4
  15. smallworld/analyses/unstable/code_coverage.py +2 -3
  16. smallworld/analyses/unstable/code_reachable.py +2 -3
  17. smallworld/analyses/unstable/control_flow_tracer.py +2 -3
  18. smallworld/analyses/unstable/pointer_finder.py +2 -3
  19. smallworld/analyses/unstable/utils/tui.py +71 -0
  20. smallworld/emulators/__init__.py +3 -1
  21. smallworld/emulators/angr/angr.py +30 -9
  22. smallworld/emulators/angr/machdefs/__init__.py +2 -0
  23. smallworld/emulators/angr/machdefs/aarch64.py +1 -1
  24. smallworld/emulators/angr/machdefs/amd64.py +0 -4
  25. smallworld/emulators/angr/machdefs/arm.py +0 -2
  26. smallworld/emulators/angr/machdefs/i386.py +0 -2
  27. smallworld/emulators/angr/machdefs/loongarch.py +340 -0
  28. smallworld/emulators/angr/machdefs/machdef.py +1 -8
  29. smallworld/emulators/angr/machdefs/mips.py +0 -2
  30. smallworld/emulators/angr/machdefs/mips64.py +0 -2
  31. smallworld/emulators/angr/machdefs/ppc.py +1 -2
  32. smallworld/emulators/angr/machdefs/riscv.py +8 -10
  33. smallworld/emulators/angr/machdefs/xtensa.py +7 -4
  34. smallworld/emulators/emulator.py +22 -0
  35. smallworld/emulators/ghidra/__init__.py +37 -0
  36. smallworld/emulators/ghidra/ghidra.py +513 -0
  37. smallworld/emulators/ghidra/machdefs/__init__.py +31 -0
  38. smallworld/emulators/ghidra/machdefs/aarch64.py +289 -0
  39. smallworld/emulators/ghidra/machdefs/amd64.py +185 -0
  40. smallworld/emulators/ghidra/machdefs/arm.py +370 -0
  41. smallworld/emulators/ghidra/machdefs/i386.py +109 -0
  42. smallworld/emulators/ghidra/machdefs/loongarch.py +162 -0
  43. smallworld/emulators/ghidra/machdefs/machdef.py +81 -0
  44. smallworld/emulators/ghidra/machdefs/mips.py +163 -0
  45. smallworld/emulators/ghidra/machdefs/mips64.py +186 -0
  46. smallworld/emulators/ghidra/machdefs/ppc.py +98 -0
  47. smallworld/emulators/ghidra/machdefs/riscv.py +208 -0
  48. smallworld/emulators/ghidra/machdefs/xtensa.py +21 -0
  49. smallworld/emulators/ghidra/typing.py +28 -0
  50. smallworld/emulators/hookable.py +18 -4
  51. smallworld/emulators/panda/machdefs/__init__.py +2 -2
  52. smallworld/emulators/panda/machdefs/aarch64.py +186 -11
  53. smallworld/emulators/panda/machdefs/amd64.py +103 -11
  54. smallworld/emulators/panda/machdefs/arm.py +216 -20
  55. smallworld/emulators/panda/machdefs/i386.py +30 -7
  56. smallworld/emulators/panda/machdefs/machdef.py +9 -16
  57. smallworld/emulators/panda/machdefs/mips.py +49 -5
  58. smallworld/emulators/panda/machdefs/mips64.py +57 -5
  59. smallworld/emulators/panda/machdefs/ppc.py +38 -13
  60. smallworld/emulators/panda/panda.py +146 -44
  61. smallworld/emulators/unicorn/__init__.py +2 -0
  62. smallworld/emulators/unicorn/machdefs/aarch64.py +253 -264
  63. smallworld/emulators/unicorn/machdefs/amd64.py +254 -259
  64. smallworld/emulators/unicorn/machdefs/arm.py +200 -212
  65. smallworld/emulators/unicorn/machdefs/i386.py +84 -90
  66. smallworld/emulators/unicorn/machdefs/machdef.py +2 -23
  67. smallworld/emulators/unicorn/machdefs/mips.py +127 -135
  68. smallworld/emulators/unicorn/unicorn.py +52 -13
  69. smallworld/helpers.py +4 -19
  70. smallworld/hinting/hinting.py +22 -192
  71. smallworld/hinting/hints.py +50 -18
  72. smallworld/instructions/bsid.py +8 -8
  73. smallworld/logging.py +4 -2
  74. smallworld/platforms/__init__.py +12 -0
  75. smallworld/platforms/defs/__init__.py +36 -0
  76. smallworld/platforms/defs/aarch64.py +450 -0
  77. smallworld/platforms/defs/amd64.py +463 -0
  78. smallworld/platforms/defs/arm.py +519 -0
  79. smallworld/platforms/defs/i386.py +258 -0
  80. smallworld/platforms/defs/loongarch.py +270 -0
  81. smallworld/platforms/defs/mips.py +321 -0
  82. smallworld/platforms/defs/mips64.py +313 -0
  83. smallworld/platforms/defs/platformdef.py +97 -0
  84. smallworld/platforms/defs/powerpc.py +259 -0
  85. smallworld/platforms/defs/riscv.py +257 -0
  86. smallworld/platforms/defs/xtensa.py +96 -0
  87. smallworld/{platforms.py → platforms/platforms.py} +3 -0
  88. smallworld/state/cpus/__init__.py +2 -0
  89. smallworld/state/cpus/aarch64.py +0 -9
  90. smallworld/state/cpus/amd64.py +6 -28
  91. smallworld/state/cpus/arm.py +0 -11
  92. smallworld/state/cpus/cpu.py +0 -11
  93. smallworld/state/cpus/i386.py +0 -7
  94. smallworld/state/cpus/loongarch.py +299 -0
  95. smallworld/state/cpus/mips.py +4 -47
  96. smallworld/state/cpus/mips64.py +18 -58
  97. smallworld/state/cpus/powerpc.py +2 -9
  98. smallworld/state/cpus/riscv.py +1 -11
  99. smallworld/state/cpus/xtensa.py +0 -5
  100. smallworld/state/memory/code.py +38 -2
  101. smallworld/state/memory/elf/__init__.py +5 -1
  102. smallworld/state/memory/elf/coredump/__init__.py +3 -0
  103. smallworld/state/memory/elf/coredump/coredump.py +46 -0
  104. smallworld/state/memory/elf/coredump/prstatus/__init__.py +27 -0
  105. smallworld/state/memory/elf/coredump/prstatus/aarch64.py +46 -0
  106. smallworld/state/memory/elf/coredump/prstatus/amd64.py +40 -0
  107. smallworld/state/memory/elf/coredump/prstatus/arm.py +53 -0
  108. smallworld/state/memory/elf/coredump/prstatus/i386.py +30 -0
  109. smallworld/state/memory/elf/coredump/prstatus/mips.py +55 -0
  110. smallworld/state/memory/elf/coredump/prstatus/mips64.py +57 -0
  111. smallworld/state/memory/elf/coredump/prstatus/ppc.py +82 -0
  112. smallworld/state/memory/elf/coredump/prstatus/prstatus.py +129 -0
  113. smallworld/state/memory/elf/elf.py +211 -57
  114. smallworld/state/memory/elf/register_state.py +36 -0
  115. smallworld/state/memory/elf/rela/__init__.py +2 -0
  116. smallworld/state/memory/elf/rela/aarch64.py +3 -1
  117. smallworld/state/memory/elf/rela/amd64.py +4 -2
  118. smallworld/state/memory/elf/rela/arm.py +4 -2
  119. smallworld/state/memory/elf/rela/i386.py +4 -2
  120. smallworld/state/memory/elf/rela/loongarch.py +32 -0
  121. smallworld/state/memory/elf/rela/mips.py +39 -18
  122. smallworld/state/memory/elf/rela/ppc.py +31 -14
  123. smallworld/state/memory/elf/structs.py +3 -0
  124. smallworld/state/memory/heap.py +2 -2
  125. smallworld/state/memory/memory.py +18 -0
  126. smallworld/state/memory/pe/__init__.py +3 -0
  127. smallworld/state/memory/pe/pe.py +361 -0
  128. smallworld/state/memory/pe/structs.py +60 -0
  129. smallworld/state/memory/stack/__init__.py +2 -0
  130. smallworld/state/memory/stack/loongarch.py +26 -0
  131. smallworld/state/models/__init__.py +29 -2
  132. smallworld/state/models/aarch64/__init__.py +1 -0
  133. smallworld/state/models/aarch64/systemv/__init__.py +6 -0
  134. smallworld/state/models/aarch64/systemv/c99/__init__.py +12 -0
  135. smallworld/state/models/aarch64/systemv/c99/signal.py +16 -0
  136. smallworld/state/models/aarch64/systemv/c99/stdio.py +265 -0
  137. smallworld/state/models/aarch64/systemv/c99/stdlib.py +169 -0
  138. smallworld/state/models/aarch64/systemv/c99/string.py +139 -0
  139. smallworld/state/models/aarch64/systemv/c99/time.py +61 -0
  140. smallworld/state/models/aarch64/systemv/posix/__init__.py +6 -0
  141. smallworld/state/models/aarch64/systemv/posix/libgen.py +16 -0
  142. smallworld/state/models/aarch64/systemv/posix/signal.py +157 -0
  143. smallworld/state/models/aarch64/systemv/systemv.py +80 -0
  144. smallworld/state/models/amd64/__init__.py +1 -0
  145. smallworld/state/models/amd64/systemv/__init__.py +6 -0
  146. smallworld/state/models/amd64/systemv/c99/__init__.py +12 -0
  147. smallworld/state/models/amd64/systemv/c99/signal.py +16 -0
  148. smallworld/state/models/amd64/systemv/c99/stdio.py +265 -0
  149. smallworld/state/models/amd64/systemv/c99/stdlib.py +169 -0
  150. smallworld/state/models/amd64/systemv/c99/string.py +139 -0
  151. smallworld/state/models/amd64/systemv/c99/time.py +61 -0
  152. smallworld/state/models/amd64/systemv/posix/__init__.py +6 -0
  153. smallworld/state/models/amd64/systemv/posix/libgen.py +16 -0
  154. smallworld/state/models/amd64/systemv/posix/signal.py +157 -0
  155. smallworld/state/models/amd64/systemv/systemv.py +78 -0
  156. smallworld/state/models/armel/__init__.py +1 -0
  157. smallworld/state/models/armel/systemv/__init__.py +6 -0
  158. smallworld/state/models/armel/systemv/c99/__init__.py +12 -0
  159. smallworld/state/models/armel/systemv/c99/signal.py +16 -0
  160. smallworld/state/models/armel/systemv/c99/stdio.py +265 -0
  161. smallworld/state/models/armel/systemv/c99/stdlib.py +169 -0
  162. smallworld/state/models/armel/systemv/c99/string.py +139 -0
  163. smallworld/state/models/armel/systemv/c99/time.py +61 -0
  164. smallworld/state/models/armel/systemv/posix/__init__.py +6 -0
  165. smallworld/state/models/armel/systemv/posix/libgen.py +16 -0
  166. smallworld/state/models/armel/systemv/posix/signal.py +157 -0
  167. smallworld/state/models/armel/systemv/systemv.py +82 -0
  168. smallworld/state/models/armhf/__init__.py +1 -0
  169. smallworld/state/models/armhf/systemv/__init__.py +6 -0
  170. smallworld/state/models/armhf/systemv/c99/__init__.py +12 -0
  171. smallworld/state/models/armhf/systemv/c99/signal.py +16 -0
  172. smallworld/state/models/armhf/systemv/c99/stdio.py +265 -0
  173. smallworld/state/models/armhf/systemv/c99/stdlib.py +169 -0
  174. smallworld/state/models/armhf/systemv/c99/string.py +139 -0
  175. smallworld/state/models/armhf/systemv/c99/time.py +61 -0
  176. smallworld/state/models/armhf/systemv/posix/__init__.py +6 -0
  177. smallworld/state/models/armhf/systemv/posix/libgen.py +16 -0
  178. smallworld/state/models/armhf/systemv/posix/signal.py +157 -0
  179. smallworld/state/models/armhf/systemv/systemv.py +77 -0
  180. smallworld/state/models/c99/__init__.py +12 -0
  181. smallworld/state/models/c99/fmt_print.py +915 -0
  182. smallworld/state/models/c99/fmt_scan.py +864 -0
  183. smallworld/state/models/c99/math.py +362 -0
  184. smallworld/state/models/c99/signal.py +71 -0
  185. smallworld/state/models/c99/stdio.py +1305 -0
  186. smallworld/state/models/c99/stdlib.py +595 -0
  187. smallworld/state/models/c99/string.py +674 -0
  188. smallworld/state/models/c99/time.py +340 -0
  189. smallworld/state/models/c99/utils.py +89 -0
  190. smallworld/state/models/cstd.py +759 -0
  191. smallworld/state/models/errno.py +581 -0
  192. smallworld/state/models/filedesc.py +515 -0
  193. smallworld/state/models/i386/__init__.py +1 -0
  194. smallworld/state/models/i386/systemv/__init__.py +6 -0
  195. smallworld/state/models/i386/systemv/c99/__init__.py +12 -0
  196. smallworld/state/models/i386/systemv/c99/signal.py +16 -0
  197. smallworld/state/models/i386/systemv/c99/stdio.py +265 -0
  198. smallworld/state/models/i386/systemv/c99/stdlib.py +169 -0
  199. smallworld/state/models/i386/systemv/c99/string.py +139 -0
  200. smallworld/state/models/i386/systemv/c99/time.py +61 -0
  201. smallworld/state/models/i386/systemv/posix/__init__.py +6 -0
  202. smallworld/state/models/i386/systemv/posix/libgen.py +16 -0
  203. smallworld/state/models/i386/systemv/posix/signal.py +157 -0
  204. smallworld/state/models/i386/systemv/systemv.py +71 -0
  205. smallworld/state/models/loongarch64/__init__.py +1 -0
  206. smallworld/state/models/loongarch64/systemv/__init__.py +6 -0
  207. smallworld/state/models/loongarch64/systemv/c99/__init__.py +12 -0
  208. smallworld/state/models/loongarch64/systemv/c99/signal.py +16 -0
  209. smallworld/state/models/loongarch64/systemv/c99/stdio.py +265 -0
  210. smallworld/state/models/loongarch64/systemv/c99/stdlib.py +169 -0
  211. smallworld/state/models/loongarch64/systemv/c99/string.py +139 -0
  212. smallworld/state/models/loongarch64/systemv/c99/time.py +61 -0
  213. smallworld/state/models/loongarch64/systemv/posix/__init__.py +6 -0
  214. smallworld/state/models/loongarch64/systemv/posix/libgen.py +16 -0
  215. smallworld/state/models/loongarch64/systemv/posix/signal.py +157 -0
  216. smallworld/state/models/loongarch64/systemv/systemv.py +83 -0
  217. smallworld/state/models/mips/__init__.py +1 -0
  218. smallworld/state/models/mips/systemv/__init__.py +6 -0
  219. smallworld/state/models/mips/systemv/c99/__init__.py +12 -0
  220. smallworld/state/models/mips/systemv/c99/signal.py +16 -0
  221. smallworld/state/models/mips/systemv/c99/stdio.py +265 -0
  222. smallworld/state/models/mips/systemv/c99/stdlib.py +169 -0
  223. smallworld/state/models/mips/systemv/c99/string.py +139 -0
  224. smallworld/state/models/mips/systemv/c99/time.py +61 -0
  225. smallworld/state/models/mips/systemv/posix/__init__.py +6 -0
  226. smallworld/state/models/mips/systemv/posix/libgen.py +16 -0
  227. smallworld/state/models/mips/systemv/posix/signal.py +157 -0
  228. smallworld/state/models/mips/systemv/systemv.py +78 -0
  229. smallworld/state/models/mips64/__init__.py +1 -0
  230. smallworld/state/models/mips64/systemv/__init__.py +6 -0
  231. smallworld/state/models/mips64/systemv/c99/__init__.py +12 -0
  232. smallworld/state/models/mips64/systemv/c99/signal.py +16 -0
  233. smallworld/state/models/mips64/systemv/c99/stdio.py +265 -0
  234. smallworld/state/models/mips64/systemv/c99/stdlib.py +169 -0
  235. smallworld/state/models/mips64/systemv/c99/string.py +139 -0
  236. smallworld/state/models/mips64/systemv/c99/time.py +61 -0
  237. smallworld/state/models/mips64/systemv/posix/__init__.py +6 -0
  238. smallworld/state/models/mips64/systemv/posix/libgen.py +16 -0
  239. smallworld/state/models/mips64/systemv/posix/signal.py +157 -0
  240. smallworld/state/models/mips64/systemv/systemv.py +98 -0
  241. smallworld/state/models/mips64el/__init__.py +1 -0
  242. smallworld/state/models/mips64el/systemv/__init__.py +6 -0
  243. smallworld/state/models/mips64el/systemv/c99/__init__.py +12 -0
  244. smallworld/state/models/mips64el/systemv/c99/signal.py +16 -0
  245. smallworld/state/models/mips64el/systemv/c99/stdio.py +265 -0
  246. smallworld/state/models/mips64el/systemv/c99/stdlib.py +169 -0
  247. smallworld/state/models/mips64el/systemv/c99/string.py +139 -0
  248. smallworld/state/models/mips64el/systemv/c99/time.py +61 -0
  249. smallworld/state/models/mips64el/systemv/posix/__init__.py +6 -0
  250. smallworld/state/models/mips64el/systemv/posix/libgen.py +16 -0
  251. smallworld/state/models/mips64el/systemv/posix/signal.py +157 -0
  252. smallworld/state/models/mips64el/systemv/systemv.py +96 -0
  253. smallworld/state/models/mipsel/__init__.py +1 -0
  254. smallworld/state/models/mipsel/systemv/__init__.py +6 -0
  255. smallworld/state/models/mipsel/systemv/c99/__init__.py +12 -0
  256. smallworld/state/models/mipsel/systemv/c99/signal.py +16 -0
  257. smallworld/state/models/mipsel/systemv/c99/stdio.py +265 -0
  258. smallworld/state/models/mipsel/systemv/c99/stdlib.py +169 -0
  259. smallworld/state/models/mipsel/systemv/c99/string.py +139 -0
  260. smallworld/state/models/mipsel/systemv/c99/time.py +61 -0
  261. smallworld/state/models/mipsel/systemv/posix/__init__.py +6 -0
  262. smallworld/state/models/mipsel/systemv/posix/libgen.py +16 -0
  263. smallworld/state/models/mipsel/systemv/posix/signal.py +157 -0
  264. smallworld/state/models/mipsel/systemv/systemv.py +78 -0
  265. smallworld/state/models/model.py +27 -2
  266. smallworld/state/models/posix/__init__.py +6 -0
  267. smallworld/state/models/posix/libgen.py +123 -0
  268. smallworld/state/models/posix/signal.py +690 -0
  269. smallworld/state/models/powerpc/__init__.py +1 -0
  270. smallworld/state/models/powerpc/systemv/__init__.py +6 -0
  271. smallworld/state/models/powerpc/systemv/c99/__init__.py +12 -0
  272. smallworld/state/models/powerpc/systemv/c99/signal.py +16 -0
  273. smallworld/state/models/powerpc/systemv/c99/stdio.py +265 -0
  274. smallworld/state/models/powerpc/systemv/c99/stdlib.py +169 -0
  275. smallworld/state/models/powerpc/systemv/c99/string.py +139 -0
  276. smallworld/state/models/powerpc/systemv/c99/time.py +61 -0
  277. smallworld/state/models/powerpc/systemv/posix/__init__.py +6 -0
  278. smallworld/state/models/powerpc/systemv/posix/libgen.py +16 -0
  279. smallworld/state/models/powerpc/systemv/posix/signal.py +157 -0
  280. smallworld/state/models/powerpc/systemv/systemv.py +93 -0
  281. smallworld/state/models/riscv64/__init__.py +1 -0
  282. smallworld/state/models/riscv64/systemv/__init__.py +6 -0
  283. smallworld/state/models/riscv64/systemv/c99/__init__.py +12 -0
  284. smallworld/state/models/riscv64/systemv/c99/signal.py +16 -0
  285. smallworld/state/models/riscv64/systemv/c99/stdio.py +265 -0
  286. smallworld/state/models/riscv64/systemv/c99/stdlib.py +169 -0
  287. smallworld/state/models/riscv64/systemv/c99/string.py +139 -0
  288. smallworld/state/models/riscv64/systemv/c99/time.py +61 -0
  289. smallworld/state/models/riscv64/systemv/posix/__init__.py +6 -0
  290. smallworld/state/models/riscv64/systemv/posix/libgen.py +16 -0
  291. smallworld/state/models/riscv64/systemv/posix/signal.py +157 -0
  292. smallworld/state/models/riscv64/systemv/systemv.py +85 -0
  293. smallworld/state/state.py +65 -24
  294. smallworld/state/unstable/elf.py +16 -31
  295. smallworld/utils.py +6 -1
  296. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/METADATA +74 -42
  297. smallworld_re-2.0.0.dist-info/RECORD +374 -0
  298. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/WHEEL +1 -1
  299. smallworld/state/models/x86/__init__.py +0 -2
  300. smallworld/state/models/x86/microsoftcdecl.py +0 -35
  301. smallworld/state/models/x86/systemv.py +0 -240
  302. smallworld_re-1.0.3.dist-info/RECORD +0 -166
  303. /smallworld/state/models/{posix.py → _posix.py} +0 -0
  304. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/entry_points.txt +0 -0
  305. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/licenses/LICENSE.txt +0 -0
  306. {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/top_level.txt +0 -0
@@ -70,9 +70,12 @@ class UnicornEmulator(
70
70
  def __init__(self, platform: platforms.Platform):
71
71
  super().__init__(platform)
72
72
  self.platform = platform
73
+ self.platdef = platforms.PlatformDef.for_platform(self.platform)
73
74
  self.machdef = UnicornMachineDef.for_platform(self.platform)
74
75
  self.engine = unicorn.Uc(self.machdef.uc_arch, self.machdef.uc_mode)
75
- self.disassembler = capstone.Cs(self.machdef.cs_arch, self.machdef.cs_mode)
76
+ self.disassembler = capstone.Cs(
77
+ self.platdef.capstone_arch, self.platdef.capstone_mode
78
+ )
76
79
  self.disassembler.detail = True
77
80
 
78
81
  self.memory_map: utils.RangeCollection = utils.RangeCollection()
@@ -180,7 +183,7 @@ class UnicornEmulator(
180
183
 
181
184
  def mem_read_callback(uc, type, address, size, value, user_data):
182
185
  assert type == unicorn.UC_MEM_READ
183
- orig_data = (value.to_bytes(size, self.platform.byteorder.value),)
186
+ orig_data = value.to_bytes(size, self.platform.byteorder.value)
184
187
  if self.all_reads_hook:
185
188
  data = self.all_reads_hook(self, address, size, orig_data)
186
189
  if data:
@@ -191,7 +194,7 @@ class UnicornEmulator(
191
194
  uc.mem_write(address, data)
192
195
  orig_data = data
193
196
 
194
- if cb := self.is_memory_read_hooked(address):
197
+ if cb := self.is_memory_read_hooked(address, size):
195
198
  data = cb(self, address, size, orig_data)
196
199
 
197
200
  # Execute registered callback
@@ -216,7 +219,7 @@ class UnicornEmulator(
216
219
  value.to_bytes(size, self.platform.byteorder.value),
217
220
  )
218
221
 
219
- if cb := self.is_memory_write_hooked(address):
222
+ if cb := self.is_memory_write_hooked(address, size):
220
223
  cb(
221
224
  self,
222
225
  address,
@@ -280,14 +283,26 @@ class UnicornEmulator(
280
283
  name = name.lower()
281
284
  # support some generic register references
282
285
  if name == "pc":
283
- name = self.machdef.pc_reg
284
- return self.machdef.uc_reg(name)
286
+ name = self.platdef.pc_register
287
+
288
+ uc_const = self.machdef.uc_reg(name)
289
+ reg = self.platdef.registers[name]
290
+
291
+ if hasattr(reg, "parent"):
292
+ parent = reg.parent
293
+ offset = reg.offset
294
+ else:
295
+ parent = reg.name
296
+ offset = 0
297
+
298
+ return (uc_const, parent, reg.size, offset)
285
299
 
286
300
  def read_register_content(self, name: str) -> int:
287
301
  (reg, _, _, _) = self._register(name)
288
302
  if reg == 0:
289
- return 0
290
- # logger.warn(f"Unicorn doesn't support register {name} for {self.platform}")
303
+ raise exceptions.UnsupportedRegisterError(
304
+ "Unicorn does not support register {name} for {self.platform}"
305
+ )
291
306
  try:
292
307
  return self.engine.reg_read(reg)
293
308
  except Exception as e:
@@ -354,7 +369,7 @@ class UnicornEmulator(
354
369
  if size > sys.maxsize:
355
370
  raise ValueError(f"{size} is too large (max: {sys.maxsize})")
356
371
  try:
357
- return self.engine.mem_read(address, size)
372
+ return bytes(self.engine.mem_read(address, size))
358
373
  except unicorn.UcError as e:
359
374
  logger.warn(f"Unicorn raised an exception on memory read {e}")
360
375
  self._error(e, "mem")
@@ -514,7 +529,7 @@ class UnicornEmulator(
514
529
 
515
530
  if pc not in self.function_hooks:
516
531
  disas = self.current_instruction()
517
- logger.info(f"single step at 0x{pc:x}: {disas}")
532
+ logger.debug(f"single step at 0x{pc:x}: {disas}")
518
533
 
519
534
  try:
520
535
  self.engine.emu_start(pc, exit_point)
@@ -587,11 +602,15 @@ class UnicornEmulator(
587
602
  pc = self.read_register("pc")
588
603
 
589
604
  try:
590
- code = self.read_memory(pc, 16)
605
+ # NB: can't use self.read_memory here since if it has an exception it will call _error, itself.
606
+ code = bytes(self.engine.mem_read(pc, 16))
591
607
  insns, _ = self._disassemble(code, pc, 1)
592
608
  i = instructions.Instruction.from_capstone(insns[0])
593
609
  except:
594
610
  # looks like that code is not available
611
+ logger.warn(
612
+ f"FYI Unicorn rich exception processing unable to read code at pc=0x{pc:x} bc it is unavailable"
613
+ )
595
614
  i = None
596
615
 
597
616
  exc: typing.Type[exceptions.EmulationError] = exceptions.EmulationError
@@ -614,11 +633,31 @@ class UnicornEmulator(
614
633
  if type(rw) is instructions.BSIDMemoryReferenceOperand:
615
634
  a = rw.address(self)
616
635
  if not (self._is_address_mapped(a)):
617
- out.append(rw)
636
+ out.append((rw, a))
618
637
  return out
619
638
 
620
639
  details: typing.Dict[typing.Union[str, int], typing.Union[str, int, bytes]] = {}
621
640
 
641
+ def details_str(details):
642
+ for k, v in details.items():
643
+ if k == "pc":
644
+ return f" pc=0x{pc:x}"
645
+ if "_reads" in k or "_writes" in k:
646
+ s = ""
647
+ for rw, a in v:
648
+ rws = str(rw)
649
+ import re
650
+
651
+ foo = re.search(r"\((.*)\)$", rws)
652
+ rw = foo.groups()[0]
653
+ x = f"address=0x{a:x} i.e. [{rw}]"
654
+ if s == "":
655
+ s = x
656
+ else:
657
+ s = s + ", " + x
658
+ return s
659
+ return "None"
660
+
622
661
  if error.errno == unicorn.UC_ERR_READ_UNMAPPED:
623
662
  msg = f"{prefix} due to read of unmapped memory"
624
663
  # actually this is a memory read error
@@ -670,7 +709,7 @@ class UnicornEmulator(
670
709
  else:
671
710
  msg = f"{prefix} due to unknown Unicorn error {error.errno}"
672
711
 
673
- raise exc(error, pc, msg, details)
712
+ raise exc(error, pc, msg + " " + details_str(details), details)
674
713
 
675
714
  def __repr__(self) -> str:
676
715
  return f"UnicornEmulator(platform={self.platform})"
smallworld/helpers.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ import copy
2
3
  import logging
3
4
  import typing
4
5
 
@@ -12,7 +13,7 @@ T = typing.TypeVar("T", bound=state.Machine)
12
13
 
13
14
  def analyze(
14
15
  machine: state.Machine,
15
- asys: typing.List[typing.Union[analyses.Analysis, analyses.Filter]],
16
+ asys: typing.List[analyses.Analysis],
16
17
  ) -> None:
17
18
  """Run requested analyses on some code
18
19
 
@@ -20,24 +21,8 @@ def analyze(
20
21
  machine: A state class from which emulation should begin.
21
22
  asys: List of analyses and filters to run
22
23
  """
23
-
24
- filters: typing.List[analyses.Filter] = []
25
- runners: typing.List[analyses.Analysis] = []
26
- for analysis in asys:
27
- if isinstance(analysis, analyses.Filter):
28
- filters.append(analysis)
29
- filters[-1].activate()
30
- elif isinstance(analysis, analyses.Analysis):
31
- runners.append(analysis)
32
-
33
- try:
34
- for analysis in runners:
35
- analysis.run(machine)
36
- except:
37
- logger.exception("Error durring analysis")
38
- finally:
39
- for filter in filters:
40
- filter.deactivate()
24
+ for a in asys:
25
+ a.run(copy.deepcopy(machine))
41
26
 
42
27
 
43
28
  def fuzz(
@@ -1,39 +1,15 @@
1
1
  import copy
2
2
  import json
3
3
  import logging
4
- import sys
5
- import typing
6
- from dataclasses import dataclass
4
+ from collections.abc import Callable
5
+ from dataclasses import asdict, dataclass
6
+ from typing import Dict, List, Type
7
7
 
8
- """
9
- Will this appear in docs?
10
-
11
-
12
- """
13
-
14
- # logging re-exports
15
- from logging import WARNING
16
-
17
- from .. import logging as internal_logging
18
-
19
-
20
- class Serializable:
21
- """Base class for serialization support.
22
-
23
- Descendants should implement the methods below to allow automatic
24
- serialization/deserialization using the JSON encoder/decoder classes below.
25
- """
26
-
27
- def to_dict(self) -> dict:
28
- raise NotImplementedError()
29
-
30
- @classmethod
31
- def from_dict(cls, dict):
32
- raise NotImplementedError()
8
+ logger = logging.getLogger(__name__)
33
9
 
34
10
 
35
11
  @dataclass(frozen=True)
36
- class Hint(Serializable):
12
+ class Hint:
37
13
  """Base class for all Hints.
38
14
 
39
15
  Arguments:
@@ -43,172 +19,26 @@ class Hint(Serializable):
43
19
  message: str
44
20
  """A detailed description."""
45
21
 
46
- def to_dict(self) -> dict:
47
- """Convert to a dictionary which can be trivially serialized.
48
-
49
- Returns:
50
- A dictionary containing the hint.
51
- """
52
-
53
- return self.__dict__
54
-
55
- @classmethod
56
- def from_dict(cls, dict):
57
- """Load from a dictionary.
58
-
59
- Arguments:
60
- dict: Dictionary from which to construct the hint.
61
-
62
- Returns:
63
- The constructed hint.
64
- """
65
-
66
- return cls(**dict)
67
-
68
-
69
- class Hinter(logging.Logger):
70
- """A custom logger that only accepts Hints."""
71
-
72
- def _log(self, level, msg, *args, **kwargs):
73
- if not isinstance(msg, Hint):
74
- raise ValueError(f"{repr(msg)} is not a Hint")
75
-
76
- return super()._log(level, msg, *args, **kwargs)
77
-
78
-
79
- root = Hinter(name="root", level=WARNING)
80
- Hinter.root = typing.cast(logging.RootLogger, root)
81
- Hinter.manager = logging.Manager(Hinter.root)
82
- Hinter.manager.loggerClass = Hinter
83
-
84
-
85
- def get_hinter(name: typing.Optional[str] = None) -> Hinter:
86
- """Get a hinter with the given name.
87
-
88
- Arguments:
89
- name: The name of the hinter to get - if `None` this returns the
90
- root Hinter.
91
-
92
- Returns:
93
- A Hinter with the given name.
94
- """
95
-
96
- if not name or isinstance(name, str) and name == root.name:
97
- return root
98
-
99
- return typing.cast(Hinter, Hinter.manager.getLogger(name))
100
-
101
-
102
- class SerializableJSONEncoder(json.JSONEncoder):
103
- def default(self, o):
104
- if isinstance(o, Serializable):
105
- d = o.to_dict()
106
- d["class"] = f"{o.__class__.__module__}.{o.__class__.__name__}"
107
-
108
- return d
109
- return super().default(o)
110
-
111
-
112
- class SerializableJSONDecoder(json.JSONDecoder):
113
- def __init__(self, *args, **kwargs):
114
- json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
115
-
116
- def object_hook(self, dict):
117
- if "class" in dict:
118
- module, name = dict["class"].rsplit(".", 1)
119
- cls = getattr(sys.modules[module], name)
120
- del dict["class"]
121
-
122
- return cls.from_dict(dict)
123
- return dict
124
-
125
-
126
- class JSONFormatter(logging.Formatter):
127
- """A custom JSON formatter for json-serializable messages.
128
-
129
- Arguments:
130
- keys (dict): A dictionary mapping json keys to their logging format
131
- strings.
132
- """
133
-
134
- def __init__(self, *args, keys=None, **kwargs):
135
- super().__init__(*args, **kwargs)
136
-
137
- keys = keys or {}
138
- self.keys = {}
139
- for name, fmt in keys.items():
140
- self.keys[name] = logging.Formatter(fmt)
141
-
142
- def format(self, record):
143
- formatted = {}
144
-
145
- for key, formatter in self.keys.items():
146
- formatted[key] = formatter.format(record)
147
-
148
- formatted["content"] = record.msg
149
-
150
- hint, record.msg = record.msg, None
151
- modified = copy.deepcopy(record)
152
- record.msg = hint
153
-
154
- modified.msg = json.dumps(formatted, cls=SerializableJSONEncoder)
155
-
156
- return super().format(modified)
157
-
158
-
159
- def setup_hinting(
160
- level: int = logging.INFO,
161
- verbose: bool = False,
162
- colors: bool = True,
163
- stream: bool = True,
164
- file: typing.Optional[str] = None,
165
- ) -> None:
166
- """Set up hint handling.
167
-
168
- Note:
169
- This should only be called once.
170
-
171
- Arguments:
172
- level: Hinting level (from `hinting` module).
173
- verbose: Enable verbose hinting mode.
174
- colors: Enable hinting colors (if supported).
175
- stream: Enable stream logging.
176
- file: If provided, enable file logging to the path provided.
177
- """
178
-
179
- if verbose:
180
- keys = {
181
- "time": "%(asctime)s",
182
- "level": "%(levelname)s",
183
- "source": "%(name)s",
184
- }
185
- else:
186
- keys = {}
187
-
188
- root = get_hinter()
189
- root.setLevel(level)
190
-
191
- if stream:
192
- format = "[%(levelchar)s] %(message)s"
193
-
194
- if colors and sys.stderr.isatty():
195
- format = f"%(levelcolor)s{format}{internal_logging.ColorLevelFilter.END}"
196
22
 
197
- formatter = JSONFormatter(format, keys=keys)
23
+ class Hinter:
24
+ def __init__(self) -> None:
25
+ self.callbacks: Dict[Type[Hint], List[Callable[[Hint], None]]] = {}
198
26
 
199
- handler: logging.Handler = logging.StreamHandler()
200
- handler.setLevel(level)
201
- handler.addFilter(internal_logging.CharacterLevelFilter())
202
- handler.addFilter(internal_logging.ColorLevelFilter())
203
- handler.setFormatter(formatter)
27
+ def register(self, clazz: Type[Hint], callback: Callable[[Hint], None]):
28
+ if clazz not in self.callbacks:
29
+ self.callbacks[clazz] = []
30
+ self.callbacks[clazz].append(callback)
204
31
 
205
- root.addHandler(handler)
32
+ def send(self, hint: Hint) -> None:
33
+ try:
34
+ logger.debug(json.dumps(asdict(hint)))
35
+ except:
36
+ logger.debug(hint.to_json()) # type: ignore
206
37
 
207
- if file:
208
- formatter = JSONFormatter("%(message)s", keys=keys)
209
- handler = logging.FileHandler(file, mode="w")
210
- handler.setFormatter(formatter)
211
- root.addHandler(handler)
38
+ clazz = hint.__class__
39
+ if clazz in self.callbacks:
40
+ for callback in self.callbacks[clazz]:
41
+ callback(copy.deepcopy(hint))
212
42
 
213
43
 
214
- __all__ = ["Hint", "Serializable", "root", "get_hinter", "setup_hinting"]
44
+ __all__ = ["Hint", "Hinter"]
@@ -1,7 +1,11 @@
1
1
  import typing
2
2
  from dataclasses import dataclass
3
3
 
4
+ import jsons
5
+ import networkx as nx
6
+
4
7
  from .. import hinting
8
+ from ..analyses.trace_execution_types import TraceElement, TraceRes
5
9
 
6
10
 
7
11
  @dataclass(frozen=True)
@@ -194,7 +198,6 @@ class InputUseHint(UnderSpecifiedValueHint):
194
198
  """
195
199
 
196
200
  input_register: str
197
- micro_exec_num: int
198
201
  instruction_num: int
199
202
  use_register: str
200
203
 
@@ -267,6 +270,32 @@ class OutputHint(hinting.Hint):
267
270
  memory: typing.Dict[int, str]
268
271
 
269
272
 
273
+ # This is used by the TraceExecutor
274
+
275
+
276
+ @dataclass(frozen=True)
277
+ class TraceExecutionHint(TypeHint):
278
+ trace: typing.List[TraceElement]
279
+ trace_digest: str
280
+ seed: int
281
+ emu_result: TraceRes
282
+ exception: typing.Optional[Exception]
283
+ exception_class: str
284
+
285
+ # note this is just for logging purposes
286
+ def to_json(self):
287
+ tracel = [te.to_json() for te in self.trace]
288
+
289
+ return {
290
+ "trace": tracel, # jsons.dump(self.trace),
291
+ "trace_digest": self.trace_digest,
292
+ "seed": jsons.dump(self.seed),
293
+ "emu_result": jsons.dump(self.emu_result),
294
+ "exception": jsons.dump(self.exception),
295
+ "exception_class": str(type(self.exception)),
296
+ }
297
+
298
+
270
299
  # These next three are used by the colorizer
271
300
 
272
301
 
@@ -286,7 +315,6 @@ class MemoryUnavailableHint(hinting.Hint):
286
315
  address: memory address of this value
287
316
  instruction: a smallworld instruction
288
317
  pc: program counter of that instruction
289
- micro_exec_num: micro-execution run number
290
318
  instruction_num: for micro-execution the instr count
291
319
  """
292
320
 
@@ -300,12 +328,11 @@ class MemoryUnavailableHint(hinting.Hint):
300
328
  scale: int
301
329
  address: int
302
330
  pc: int
303
- micro_exec_num: int
304
331
  instruction_num: int
305
332
 
306
333
 
307
334
  @dataclass(frozen=True)
308
- class MemoryUnavailableProbHint(hinting.Hint):
335
+ class MemoryUnavailableSummaryHint(hinting.Hint):
309
336
  is_read: bool
310
337
  size: int
311
338
  base_reg_name: str
@@ -313,7 +340,7 @@ class MemoryUnavailableProbHint(hinting.Hint):
313
340
  offset: int
314
341
  scale: int
315
342
  pc: int
316
- prob: float
343
+ count: int
317
344
 
318
345
 
319
346
  @dataclass(frozen=True)
@@ -324,9 +351,8 @@ class DynamicValueHint(hinting.Hint):
324
351
  Arguments:
325
352
  instruction: a smallworld instruction
326
353
  pc: program counter of that instruction
327
- micro_exec_num: micro-execution run number
328
354
  instruction_num: for micro-execution the instr count
329
- dynamic_value: this is the actual value as bytes
355
+ dynamic_value: this is the actual value
330
356
  size: the size of the value in bytes
331
357
  use: True if its a "use" of this value, else its a "def"
332
358
  new: True if its a new value, first sighting
@@ -334,9 +360,9 @@ class DynamicValueHint(hinting.Hint):
334
360
 
335
361
  # instruction: typing.Any
336
362
  pc: int
337
- micro_exec_num: int
338
363
  instruction_num: int
339
- dynamic_value: str
364
+ exec_id: int
365
+ dynamic_value: int
340
366
  color: int
341
367
  size: int
342
368
  use: bool
@@ -354,7 +380,6 @@ class DynamicRegisterValueHint(DynamicValueHint):
354
380
  use: True if its a "use" of this value, else its a "def"
355
381
  capstone_instruction: the instruction in capstone parlance
356
382
  pc: program counter of that instruction
357
- micro_exec_num: micro-execution run number
358
383
  instruction_num: for micro-execution the instr count
359
384
  info: extra info about use or def if available
360
385
  """
@@ -377,7 +402,6 @@ class DynamicMemoryValueHint(DynamicValueHint):
377
402
  use: True if its a "use" of this value, else its a "def"
378
403
  capstone_instruction: the instruction in capstone parlance
379
404
  pc: program counter of that instruction
380
- micro_exec_num: micro-execution run number
381
405
  instruction_num: for micro-execution the instr count
382
406
  info: extra info about use or def if available
383
407
  """
@@ -390,18 +414,19 @@ class DynamicMemoryValueHint(DynamicValueHint):
390
414
 
391
415
 
392
416
  @dataclass(frozen=True)
393
- class DynamicValueProbHint(hinting.Hint):
417
+ class DynamicValueSummaryHint(hinting.Hint):
394
418
  # instruction: typing.Any
395
419
  pc: int
396
420
  color: int
397
421
  size: int
398
422
  use: bool
399
423
  new: bool
400
- prob: float
424
+ count: int
425
+ num_micro_executions: int
401
426
 
402
427
 
403
428
  @dataclass(frozen=True)
404
- class DynamicMemoryValueProbHint(DynamicValueProbHint):
429
+ class DynamicMemoryValueSummaryHint(DynamicValueSummaryHint):
405
430
  base: str
406
431
  index: str
407
432
  scale: int
@@ -409,19 +434,26 @@ class DynamicMemoryValueProbHint(DynamicValueProbHint):
409
434
 
410
435
 
411
436
  @dataclass(frozen=True)
412
- class DynamicRegisterValueProbHint(DynamicValueProbHint):
437
+ class DynamicRegisterValueSummaryHint(DynamicValueSummaryHint):
413
438
  reg_name: str
414
439
 
415
440
 
441
+ @dataclass(frozen=True)
442
+ class DefUseGraphHint(hinting.Hint):
443
+ graph: nx.MultiDiGraph
444
+
445
+
416
446
  __all__ = [
417
447
  "DynamicRegisterValueHint",
418
448
  "DynamicMemoryValueHint",
419
449
  "MemoryUnavailableHint",
420
- "DynamicRegisterValueProbHint",
421
- "DynamicMemoryValueProbHint",
422
- "MemoryUnavailableProbHint",
450
+ "DynamicRegisterValueSummaryHint",
451
+ "DynamicMemoryValueSummaryHint",
452
+ "MemoryUnavailableSummaryHint",
423
453
  "EmulationException",
424
454
  "CoverageHint",
425
455
  "ControlFlowHint",
426
456
  "ReachableCodeHint",
457
+ "DefUseGraphHint",
458
+ "TraceExecutionHint",
427
459
  ]
@@ -34,13 +34,13 @@ class BSIDMemoryReferenceOperand(MemoryReferenceOperand):
34
34
 
35
35
  return base + self.scale * index + self.offset
36
36
 
37
- # def to_json(self) -> dict:
38
- # return {
39
- # "base": self.base,
40
- # "index": self.index,
41
- # "scale": self.scale,
42
- # "offset": self.offset,
43
- # }
37
+ def to_json(self) -> dict:
38
+ return {
39
+ "base": self.base,
40
+ "index": self.index,
41
+ "scale": self.scale,
42
+ "offset": self.offset,
43
+ }
44
44
 
45
45
  @classmethod
46
46
  def from_json(cls, dict):
@@ -62,6 +62,6 @@ class BSIDMemoryReferenceOperand(MemoryReferenceOperand):
62
62
  string = f"{string}+{self.index}"
63
63
 
64
64
  if self.offset:
65
- string = f"{string}+{self.offset}"
65
+ string = f"{string}+{self.offset:x}"
66
66
 
67
67
  return f"{self.__class__.__name__}({string})"
smallworld/logging.py CHANGED
@@ -23,6 +23,8 @@ class ColorLevelFilter(logging.Filter):
23
23
 
24
24
  WHITE_DIM = "\x1b[37;2m"
25
25
  WHITE = "\x1b[37m"
26
+ NORMAL_DIM = "\x1b[0;2m"
27
+ NORMAL = "\x1b[0m"
26
28
  YELLOW = "\x1b[33m"
27
29
  RED = "\x1b[31m"
28
30
  RED_BOLD = "\x1b[31;1m"
@@ -30,8 +32,8 @@ class ColorLevelFilter(logging.Filter):
30
32
  NULL = END
31
33
 
32
34
  COLORS = {
33
- logging.DEBUG: WHITE_DIM,
34
- logging.INFO: WHITE,
35
+ logging.DEBUG: NORMAL_DIM,
36
+ logging.INFO: NORMAL,
35
37
  logging.WARNING: YELLOW,
36
38
  logging.ERROR: RED,
37
39
  logging.CRITICAL: RED_BOLD,
@@ -0,0 +1,12 @@
1
+ from .defs import PlatformDef, RegisterAliasDef, RegisterDef
2
+ from .platforms import ABI, Architecture, Byteorder, Platform
3
+
4
+ __all__ = [
5
+ "Platform",
6
+ "Architecture",
7
+ "Byteorder",
8
+ "ABI",
9
+ "PlatformDef",
10
+ "RegisterDef",
11
+ "RegisterAliasDef",
12
+ ]
@@ -0,0 +1,36 @@
1
+ from .aarch64 import AArch64
2
+ from .amd64 import AMD64, AMD64AVX512
3
+ from .arm import ARMv5T, ARMv6M, ARMv6MThumb, ARMv7A, ARMv7M, ARMv7R
4
+ from .i386 import I386
5
+ from .loongarch import LoongArch64
6
+ from .mips import MIPS32BE, MIPS32EL
7
+ from .mips64 import MIPS64BE, MIPS64EL
8
+ from .platformdef import PlatformDef, RegisterAliasDef, RegisterDef
9
+ from .powerpc import PowerPC32, PowerPC64
10
+ from .riscv import RiscV64
11
+ from .xtensa import Xtensa
12
+
13
+ __all__ = [
14
+ "AArch64",
15
+ "AMD64",
16
+ "AMD64AVX512",
17
+ "ARMv5T",
18
+ "ARMv6M",
19
+ "ARMv6MThumb",
20
+ "ARMv7M",
21
+ "ARMv7R",
22
+ "ARMv7A",
23
+ "I386",
24
+ "LoongArch64",
25
+ "MIPS32EL",
26
+ "MIPS32BE",
27
+ "MIPS64EL",
28
+ "MIPS64BE",
29
+ "PlatformDef",
30
+ "PowerPC32",
31
+ "PowerPC64",
32
+ "RegisterDef",
33
+ "RegisterAliasDef",
34
+ "RiscV64",
35
+ "Xtensa",
36
+ ]