smallworld-re 1.0.2__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 +44 -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 +225 -61
  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.2.dist-info → smallworld_re-2.0.0.dist-info}/METADATA +76 -43
  297. smallworld_re-2.0.0.dist-info/RECORD +374 -0
  298. {smallworld_re-1.0.2.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.2.dist-info/RECORD +0 -166
  303. /smallworld/state/models/{posix.py → _posix.py} +0 -0
  304. {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/entry_points.txt +0 -0
  305. {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
  306. {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,9 @@ from .....exceptions import ConfigurationError
3
3
  from ..structs import ElfRela
4
4
  from .rela import ElfRelocator
5
5
 
6
+ R_MIPS_NONE = 0
6
7
  R_MIPS_32 = 2 # 32-bit direct
8
+ R_MIPS_REL32 = 3
7
9
  R_MIPS_64 = 18 # 64-bit direct
8
10
 
9
11
 
@@ -12,24 +14,43 @@ class MIPSElfRelocator(ElfRelocator):
12
14
  byteorder = platforms.Byteorder.BIG
13
15
 
14
16
  def _compute_value(self, rela: ElfRela):
15
- # Because mypy doesn't believe I know what I'm doing...
16
-
17
- if rela.type == R_MIPS_32:
18
- # 32-bit direct
19
- val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
20
- return val.to_bytes(
21
- 4, "big" if self.byteorder == platforms.Byteorder.BIG else "little"
22
- )
23
- elif rela.type == R_MIPS_64:
24
- # 64-bit direct
25
- val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
26
- return val.to_bytes(
27
- 8, "big" if self.byteorder == platforms.Byteorder.BIG else "little"
28
- )
29
- else:
30
- raise ConfigurationError(
31
- "Invalid relocation type for {rela.symbol.name}: {rela.type}"
32
- )
17
+ # Unpack a MIPS64 relocation.
18
+ #
19
+ # It's not possible to build a 64-bit address in one instruction in MIPS64.
20
+ # Rather than tell the linker to live with it,
21
+ # MIPS64 relocation entries can define up to three nested relocations,
22
+ # with relocations 2 and 3 acting as if the symbol value were the result
23
+ # of the previous relocation.
24
+ #
25
+ # There's a fourth argument, which is a parameter to relocation 2, I think.
26
+ # Don't want to waste those bytes...
27
+ rela_types = []
28
+ # rela_special = (rela.type >> 24) & 0xFF
29
+ for i in range(0, 3):
30
+ rela_types.append((rela.type >> (i * 8)) & 0xFF)
31
+
32
+ val = rela.symbol.value + rela.symbol.baseaddr
33
+ is_64 = False
34
+ for i in range(0, 3):
35
+ rela_type = rela_types[i]
36
+ if rela_type == R_MIPS_NONE:
37
+ break
38
+ elif rela_type == R_MIPS_32 or rela_type == R_MIPS_REL32:
39
+ # 32-bit direct
40
+ val = val + rela.addend
41
+ elif rela_type == R_MIPS_64:
42
+ # 64-bit direct
43
+ val = val + rela.addend
44
+ is_64 = True
45
+ else:
46
+ raise ConfigurationError(
47
+ f"Invalid relocation type {i} for {rela.symbol.name}: {rela_type}"
48
+ )
49
+
50
+ return val.to_bytes(
51
+ 8 if is_64 else 4,
52
+ "big" if self.byteorder == platforms.Byteorder.BIG else "little",
53
+ )
33
54
 
34
55
 
35
56
  class MIPSELElfRelocator(MIPSElfRelocator):
@@ -3,6 +3,7 @@ from .....exceptions import ConfigurationError
3
3
  from ..structs import ElfRela
4
4
  from .rela import ElfRelocator
5
5
 
6
+ R_PPC_ABS32 = 1 # Direct 32-bit
6
7
  R_PPC_GLOB_DAT = 20 # Create GOT entry
7
8
  R_PPC_JUMP_SLOT = 21 # Create PLT entry
8
9
  R_PPC_RELATIVE = 22 # Adjust by program base
@@ -14,7 +15,10 @@ class PowerPCElfRelocator(ElfRelocator):
14
15
  addrsz = 4
15
16
 
16
17
  def _compute_value(self, rela: ElfRela):
17
- if (
18
+ if rela.type == R_PPC_ABS32:
19
+ val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
20
+ return val.to_bytes(4, "big")
21
+ elif (
18
22
  rela.type == R_PPC_GLOB_DAT
19
23
  or rela.type == R_PPC_JUMP_SLOT
20
24
  or rela.type == R_PPC_RELATIVE
@@ -24,22 +28,35 @@ class PowerPCElfRelocator(ElfRelocator):
24
28
  return val.to_bytes(self.addrsz, "big")
25
29
  else:
26
30
  raise ConfigurationError(
27
- "Invalid relocation type for {rela.symbol.name}: {rela.type}"
31
+ f"Invalid relocation type for {rela.symbol.name}: {rela.type}"
28
32
  )
29
33
 
30
34
 
35
+ R_PPC64_ADDR64 = 38 # Adjust by program base, I think...
36
+
37
+
31
38
  class PowerPC64ElfRelocator(PowerPCElfRelocator):
32
39
  arch = platforms.Architecture.POWERPC64
40
+ byteorder = platforms.Byteorder.BIG
33
41
  addrsz = 8
34
- # TODO: This is only the beginning
35
- #
36
- # The PowerPC64 JUMP_SLOT relocation is much more complicated,
37
- # possibly the most complicated I've ever seen.
38
- # It actually fills in three 64-bit values:
39
- #
40
- # 1. The actual function address
41
- # 2. The TOC base address; serves a similar purpose to the Global Pointer in MIPS.
42
- # 3. An "environment" pointer, not used by C.
43
- #
44
- # We're currently correctly filling in 1.
45
- # Entry 2. is the address of the GOT section of the containing binary + 0x8000.
42
+
43
+ def _compute_value(self, rela: ElfRela):
44
+ if rela.type == R_PPC64_ADDR64:
45
+ val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
46
+ return val.to_bytes(self.addrsz, "big")
47
+ elif rela.type == R_PPC_JUMP_SLOT:
48
+ # The PowerPC64 JUMP_SLOT relocation is much more complicated.
49
+ # It actually fills in three 64-bit values:
50
+ #
51
+ # 1. The actual function address
52
+ # 2. The TOC base address; serves a similar purpose to the Global Pointer in MIPS.
53
+ # 3. An "environment" pointer, not used by C.
54
+ #
55
+ # We're currently correctly filling in 1.
56
+ # Entry 2. is the address of the GOT section of the containing binary + 0x8000.
57
+ #
58
+ # This requires a reference to the containing binary,
59
+ # which I have no idea how to pass.
60
+ raise NotImplementedError("R_PPC64_JUMP_SLOT not implemented")
61
+ else:
62
+ return super()._compute_value(rela)
@@ -24,11 +24,14 @@ class ElfSymbol:
24
24
  without a separate dict.
25
25
  """
26
26
 
27
+ idx: int # Symbol table index
28
+ dynamic: bool # Is this in the static or dynamic symbol table?
27
29
  name: str # Symbol name
28
30
  type: int # Symbol type
29
31
  bind: int # Symbol binding
30
32
  visibility: int # Symbol visibility
31
33
  shndx: int # Symbol section index, or reserved flags
34
+ defined: bool # Is this symbol defined?
32
35
  value: int # Symbol value
33
36
  size: int # Symbol size
34
37
  baseaddr: int # Base address for relative symbol values
@@ -42,7 +42,7 @@ class Heap(memory.Memory):
42
42
  return self.allocate(value)
43
43
 
44
44
  def allocate_bytes(
45
- self, content: typing.Union[bytes, bytearray], label: str
45
+ self, content: typing.Union[bytes, bytearray], label: typing.Optional[str]
46
46
  ) -> int:
47
47
  """Allocate space for and write bytes to the heap.
48
48
 
@@ -79,7 +79,7 @@ class BumpAllocator(Heap):
79
79
  return self.address + offset
80
80
 
81
81
  def free(self, address: int) -> None:
82
- raise NotImplementedError("freeing with a BumpAllocator is not yet implemented")
82
+ pass
83
83
 
84
84
 
85
85
  __all__ = ["Heap", "BumpAllocator"]
@@ -114,6 +114,24 @@ class Memory(state.Stateful, dict):
114
114
  self.clear()
115
115
  self[0] = value
116
116
 
117
+ def write_bytes(self, address: int, data: bytes) -> None:
118
+ """Overwrite part of this memory region with specific bytes
119
+
120
+ This will fail if the data you want to overwrite is in a symbolic sub-region.
121
+ """
122
+
123
+ for segment_offset, segment in self.items():
124
+ segment_address = self.address + segment_offset
125
+ if address >= segment_address and address < segment_address + segment._size:
126
+ contents = segment.get_content()
127
+ if not isinstance(contents, bytes):
128
+ raise exceptions.SymbolicValueError(
129
+ f"Tried to write {len(data)} bytes at {hex(address)}; data in {segment_address:x} - {segment_address + segment._size:x} is symbolic."
130
+ )
131
+ offset = address - segment_address
132
+ contents = contents[0:offset] + data + contents[offset + len(data) :]
133
+ segment.set_content(contents)
134
+
117
135
  def __hash__(self):
118
136
  return super(dict, self).__hash__()
119
137
 
@@ -0,0 +1,3 @@
1
+ from .pe import PEExecutable
2
+
3
+ __all__ = ["PEExecutable"]
@@ -0,0 +1,361 @@
1
+ import typing
2
+
3
+ import lief
4
+
5
+ from ....exceptions import ConfigurationError
6
+ from ....platforms import Architecture, Byteorder, Platform, PlatformDef
7
+ from ....utils import RangeCollection
8
+ from ...state import BytesValue
9
+ from ..code import Executable
10
+ from .structs import PEExport, PEImport
11
+
12
+ # PE32+ machine types
13
+ # There are a lot more of these, but I can only test on amd64 and i386
14
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664
15
+ IMAGE_FILE_MACHINE_I386 = 0x14C
16
+
17
+ # Section flags
18
+ # Currently, the only one we care about is "code".
19
+ # Not sure how the others interact with file loading.
20
+ IMAGE_SCN_CNT_CODE = 0x20
21
+
22
+ # Relocation types
23
+ # All of these adjust based on the difference between
24
+ # the requested and actual load addresses
25
+ IMAGE_REL_BASED_ABSOLUTE = 0x0 # No-op
26
+ IMAGE_REL_BASED_HIGHLOW = 0x3 # Add 32-bit difference to a 32-bit value
27
+ IMAGE_REL_BASED_DIR64 = 0xA # Add 64-bit difference to a 64-bit value
28
+
29
+
30
+ class PEExecutable(Executable):
31
+ """Executable loaded from a PE32+
32
+
33
+ This loads a single PE32+ file into a SmallWorld memory object.
34
+ It performs no relocation or initialization,
35
+ just maps the file into memory as the kernel intended.
36
+
37
+ Arguments:
38
+ file: File-like object containing the image
39
+ platform: Optional platform; used for header verification
40
+ ignore_platform: Do not try to ID or verify platform from headers
41
+ user_base: Optional user-specified base address
42
+ page_size: System page size
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ file: typing.BinaryIO,
48
+ platform: typing.Optional[Platform] = None,
49
+ ignore_platform: bool = False,
50
+ user_base: typing.Optional[int] = None,
51
+ page_size: int = 0x1000,
52
+ ):
53
+ # Initialize with null address and size;
54
+ # we will update these later
55
+ super().__init__(0, 0)
56
+
57
+ self.platform = platform
58
+ self.platdef: typing.Optional[PlatformDef] = None
59
+ self.bounds: RangeCollection = RangeCollection()
60
+
61
+ self._page_size = page_size
62
+ self._user_base = user_base
63
+ self._file_base = 0
64
+
65
+ self._exports: typing.List[PEExport] = list()
66
+ self._exports_by_name: typing.Dict[typing.Tuple[str, str], PEExport] = dict()
67
+ self._exports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEExport] = dict()
68
+
69
+ self._imports: typing.List[PEImport] = list()
70
+ self._imports_by_name: typing.Dict[typing.Tuple[str, str], PEImport] = dict()
71
+ self._imports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEImport] = dict()
72
+
73
+ # Read the entire image out of the file
74
+ image = file.read()
75
+
76
+ # Use lief to check if this is a PE
77
+ # NOTE: For some reason, this takes list(int), not bytes
78
+ if not lief.is_pe(list(image)):
79
+ raise ConfigurationError("Image is not a PE")
80
+
81
+ # Use lief to parse the PE
82
+ # NOTE: For some reason, this takes list(int), not bytes
83
+ # NOTE: lief objects aren't deep-copyable.
84
+ # I'd love to keep `pe` around for later use, but I can't.
85
+ pe = lief.PE.parse(list(image))
86
+ if pe is None:
87
+ raise ConfigurationError("Failed parsing PE image")
88
+
89
+ # Check machine compatibility
90
+ if not ignore_platform:
91
+ hdr_platform = self._platform_for_chdr(pe)
92
+ if self.platform is not None:
93
+ if self.platform != hdr_platform:
94
+ raise ConfigurationError(
95
+ "Platform mismatch: "
96
+ f"specified {self.platform}, but got {hdr_platform} from header"
97
+ )
98
+ else:
99
+ self.platform = hdr_platform
100
+ self.platdef = PlatformDef.for_platform(hdr_platform)
101
+
102
+ # Determine the file base address
103
+ self._file_base = pe.imagebase
104
+ self._determine_base()
105
+
106
+ for section in pe.sections:
107
+ # TODO: How do PE32+ files distinguish loadable segments?
108
+ # mingw objdump has some notion of allocated segments,
109
+ # but it doesn't map to anything in any of the flags.
110
+ self._map_section(section, image)
111
+
112
+ # Fix up the memory image to account for changes in the base address
113
+ self._apply_base_relocations(pe)
114
+
115
+ # Compute the final total capacity
116
+ for offset, value in self.items():
117
+ self.size = max(self.size, offset + value.get_size())
118
+
119
+ # Extract exports
120
+ self._extract_exports(pe)
121
+
122
+ # Extract imports
123
+ self._extract_imports(pe)
124
+
125
+ def _platform_for_chdr(self, pe):
126
+ if pe.header.machine.value == IMAGE_FILE_MACHINE_AMD64:
127
+ return Platform(Architecture.X86_64, Byteorder.LITTLE)
128
+ elif pe.header.machine.value == IMAGE_FILE_MACHINE_I386:
129
+ return Platform(Architecture.X86_32, Byteorder.LITTLE)
130
+ else:
131
+ raise ConfigurationError(f"Unsupported machine type {pe.header.machine}")
132
+
133
+ def _determine_base(self):
134
+ if self._user_base is None:
135
+ # No user base requested
136
+ if self._file_base == 0:
137
+ # No file base defined (unusal for PE32+)
138
+ # Need the user to provide one
139
+ raise ConfigurationError(
140
+ "No base address provided, and none defined in PE file"
141
+ )
142
+ else:
143
+ self.address = self._file_base
144
+ else:
145
+ # PE files are always position-independent;
146
+ # we'll just have to fix things up later.
147
+ self.address = self._user_base
148
+
149
+ def _rebase_file(self, val: int):
150
+ # Rebase an offset from file-relative to image-relative
151
+ res = val + self.address
152
+ return res
153
+
154
+ def _page_align(self, val: int, up: bool = True):
155
+ if up:
156
+ val += self._page_size - 1
157
+ return (val // self._page_size) * self._page_size
158
+
159
+ def _map_section(self, sect, image):
160
+ # NOTE: Unlike ELFs, The physical address of PE sections is not page-aligned.
161
+ sect_start = sect.offset
162
+ sect_end = sect.offset + sect.size
163
+ sect_addr = self._page_align(self._rebase_file(sect.virtual_address), up=False)
164
+ sect_size = self._page_align(sect.virtual_size)
165
+
166
+ sect_data = image[sect_start:sect_end]
167
+ if len(sect_data) < sect_size:
168
+ # Section is shorter than what's available in the file;
169
+ # THis will get zero-padded.
170
+ pad_size = sect_size - len(sect_data)
171
+ sect_data += b"\0" * pad_size
172
+ if len(sect_data) != sect_size:
173
+ raise ConfigurationError(
174
+ f"Expected segment of size {sect_size}, but got {len(sect_data)}"
175
+ )
176
+
177
+ if 0 != (sect.characteristics & IMAGE_SCN_CNT_CODE):
178
+ # This is a code segment; add it to program bounds
179
+ self.bounds.add_range((sect_addr, sect_addr + sect_size))
180
+
181
+ sect_value = BytesValue(sect_data, None)
182
+ self[sect_addr - self.address] = sect_value
183
+
184
+ def _apply_base_relocations(self, pe):
185
+ # PE32+ files always allow the loader to override
186
+ # the program's base address.
187
+ #
188
+ # The relocation section marks places where
189
+ # an absolute offset needs fixing
190
+ # if the loader decides to override
191
+ if self.address == self._file_base:
192
+ # This file was not relocated. Nothing to do.
193
+ return
194
+
195
+ if self.platform.byteorder == Byteorder.LITTLE:
196
+ byteorder = "little"
197
+ elif self.platform.byteorder == Byteorder.BIG:
198
+ byteorder = "big"
199
+ else:
200
+ raise ConfigurationError(
201
+ f"Can't encode byteorder {self.platform.byteorder}"
202
+ )
203
+
204
+ for base_reloc in pe.relocations:
205
+ for entry in base_reloc.entries:
206
+ if entry.type.value == IMAGE_REL_BASED_ABSOLUTE:
207
+ # Entry is a no-op; continue
208
+ continue
209
+ for off, val in self.items():
210
+ if entry.address >= off and entry.address <= val.get_size():
211
+ # Find the section containing this address
212
+ contents = bytearray(val.get_content())
213
+ fix_off = entry.address - off
214
+
215
+ if entry.type.value == IMAGE_REL_BASED_HIGHLOW:
216
+ # 4-byte repair
217
+ tofix = int.from_bytes(
218
+ contents[fix_off : fix_off + 4], byteorder
219
+ )
220
+ tofix += self.address - self._file_base
221
+ contents[fix_off : fix_off + 4] = tofix.to_bytes(
222
+ 4, byteorder
223
+ )
224
+
225
+ elif entry.type.value == IMAGE_REL_BASED_DIR64:
226
+ # 8-byte repair
227
+ tofix = int.from_bytes(
228
+ contents[fix_off : fix_off + 8], byteorder
229
+ )
230
+ tofix += self.address - self._file_base
231
+ contents[fix_off : fix_off + 8] = tofix.to_bytes(
232
+ 8, byteorder
233
+ )
234
+
235
+ else:
236
+ raise ConfigurationError(
237
+ "Unhandled relocation type {entry.type}"
238
+ )
239
+ # Reset the data
240
+ val.set_content(bytes(contents))
241
+ break
242
+
243
+ def _extract_exports(self, pe) -> None:
244
+ if not pe.has_exports:
245
+ return
246
+
247
+ d = pe.get_export()
248
+ for e in d.entries:
249
+ if e.is_forwarded:
250
+ raise NotImplementedError(
251
+ "{d.name}.{e.name} is forwarded to {e.forward_information}"
252
+ )
253
+ else:
254
+ exp = PEExport(
255
+ dll=d.name,
256
+ name=e.name,
257
+ ordinal=e.ordinal,
258
+ forwarder=None,
259
+ value=e.value + self.address,
260
+ )
261
+ self._exports.append(exp)
262
+ self._exports_by_name[(d.name, e.name)] = exp
263
+ self._exports_by_ordinal[(d.name, e.ordinal)] = exp
264
+
265
+ def _extract_imports(self, pe) -> None:
266
+ if not pe.has_imports:
267
+ return
268
+
269
+ # Iterate over the import directories
270
+ # These group imports by the DLL that provides them
271
+ for d in pe.imports:
272
+ for e in d.entries:
273
+ imp = PEImport(
274
+ dll=d.name,
275
+ name=e.name if not e.is_ordinal else None,
276
+ ordinal=e.ordinal if e.is_ordinal else None,
277
+ iat_address=e.iat_address + self.address,
278
+ forwarder=None,
279
+ value=None,
280
+ )
281
+ if e.name == "puts":
282
+ print(f"puts IAT at {e.iat_address:x} or {e.iat_value:x}")
283
+ self._imports.append(imp)
284
+ if e.is_ordinal:
285
+ self._imports_by_ordinal[(d.name, e.ordinal)] = imp
286
+ else:
287
+ self._imports_by_name[(d.name, e.name)] = imp
288
+
289
+ def update_import(
290
+ self, dll: str, hint: typing.Union[str, int, PEImport], value: int
291
+ ) -> None:
292
+ """Update an imported symbol in this PE file
293
+
294
+ Arguments:
295
+ dll: Name of the DLL where the import is defined
296
+ hint: Symbol name or ordinal
297
+ value: New value of the symbol
298
+ """
299
+ # No platform specified
300
+ if self.platform is None or self.platdef is None:
301
+ raise ConfigurationError("No platform specified; can't update imports")
302
+
303
+ if isinstance(hint, str):
304
+ # Look up by name
305
+ if (dll, hint) not in self._imports_by_name:
306
+ raise ConfigurationError(
307
+ f"No import for {dll}.{hint}. Try by ordinal?"
308
+ )
309
+ imp = self._imports_by_name[(dll, hint)]
310
+ elif isinstance(hint, int):
311
+ # Look up by ordinal
312
+ if (dll, hint) not in self._imports_by_ordinal:
313
+ raise ConfigurationError(f"No import for {dll}.#{hint}. Try by name?")
314
+ imp = self._imports_by_ordinal[(dll, hint)]
315
+ elif isinstance(hint, PEImport):
316
+ imp = hint
317
+ else:
318
+ raise TypeError(f"Unexpected hint {hint} of type {type(hint)}")
319
+
320
+ # Save the new value to the import
321
+ # This marks it as initialized
322
+ imp.value = value
323
+
324
+ # Convert value to bytes
325
+ if self.platform.byteorder == Byteorder.LITTLE:
326
+ value_bytes = value.to_bytes(self.platdef.address_size, "little")
327
+ elif self.platform.byteorder == Byteorder.BIG:
328
+ value_bytes = value.to_bytes(self.platdef.address_size, "big")
329
+ else:
330
+ raise ConfigurationError(
331
+ f"Can't encode int for byteorder {self.platform.byteorder}"
332
+ )
333
+
334
+ # Rewrite IAT slot
335
+ # NOTE: PE files can have overlapping segments; check all of them.
336
+ for off, seg in self.items():
337
+ start = off + self.address
338
+ stop = start + seg.get_size()
339
+ if imp.iat_address >= start and imp.iat_address < stop:
340
+ start = imp.iat_address - start
341
+ end = start + len(value_bytes)
342
+ contents = seg.get_content()
343
+ contents = contents[0:start] + value_bytes + contents[end:]
344
+ seg.set_content(contents)
345
+
346
+ def link_pe(self, dll: "PEExecutable"):
347
+ for imp in self._imports:
348
+ if imp.value is not None:
349
+ continue
350
+
351
+ if imp.name is not None and (imp.dll, imp.name) in dll._exports_by_name:
352
+ exp = dll._exports_by_name[(imp.dll, imp.name)]
353
+ elif (
354
+ imp.ordinal is not None
355
+ and (imp.dll, imp.ordinal) in dll._exports_by_ordinal
356
+ ):
357
+ exp = dll._exports_by_ordinal[(imp.dll, imp.ordinal)]
358
+ else:
359
+ continue
360
+
361
+ self.update_import(imp.dll, imp, exp.value)
@@ -0,0 +1,60 @@
1
+ import typing
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass(frozen=False)
6
+ class PEExport:
7
+ """PE export struct
8
+
9
+ Lief parses this data, but I can't keep the objects around.
10
+
11
+ An export defines a symbol that can be imported by other images.
12
+ See 'PEImport' for more on that process.
13
+
14
+ This is a mashup of a number of PE32+ structs
15
+ (export definitions are actually somewhat complicated
16
+ compared to import definitions).
17
+
18
+ Exports can be referenced by name or by ordinal - a numeric key
19
+ specific to the DLL.
20
+
21
+ Exports can provide an actual address, or a "forwarder".
22
+ This is the name of another export in another DLL that
23
+ will provide the actual value of the symbol... or possibly forward again.
24
+ """
25
+
26
+ dll: str
27
+ ordinal: int
28
+ name: str
29
+ forwarder: typing.Optional[str]
30
+ value: int
31
+
32
+
33
+ @dataclass(frozen=False)
34
+ class PEImport:
35
+ """PE import struct
36
+
37
+ Lief parses this data, but I can't keep the objects around.
38
+
39
+ An import defines that a specific exported symbol
40
+ is required from a specific DLL file.
41
+
42
+ They are closer to a relocation entry than a symbol;
43
+ each import defines the export required, and where
44
+ to write the exported value. There is exactly one
45
+ relocation mechanism, making this a lot easier to parse than ELF.
46
+
47
+ This class actually mashes up two PE32+ structures:
48
+ an Import Directory Entry, which defines a DLL that the file needs,
49
+ and an Import Lookup Entry, which defines a specific export it needs.
50
+
51
+ Lookup requires two keys, either the DLL name and export name,
52
+ or the DLL and export ordinal - a numeric key specified wihtin the DLL.
53
+ """
54
+
55
+ dll: str # Name of the DLL
56
+ name: typing.Optional[str] # String name of the export
57
+ ordinal: typing.Optional[int] # Ordinal of the export
58
+ iat_address: int # Address of the IAT slot for this import
59
+ forwarder: typing.Optional[str] # Forwarder export, if provided
60
+ value: typing.Optional[int] # Value imported
@@ -2,6 +2,7 @@ from .aarch64 import AArch64Stack
2
2
  from .amd64 import AMD64Stack
3
3
  from .arm import ARMv5tStack, ARMv6mStack, ARMv7aStack, ARMv7mStack, ARMv7rStack
4
4
  from .i386 import X86Stack
5
+ from .loongarch import LoongArch64Stack
5
6
  from .mips import MIPSBEStack, MIPSELStack
6
7
  from .mips64 import MIPS64BEStack, MIPS64ELStack
7
8
  from .ppc import PowerPC32Stack, PowerPC64Stack
@@ -19,6 +20,7 @@ __all__ = __stack__ + [
19
20
  "ARMv7rStack",
20
21
  "ARMv7aStack",
21
22
  "X86Stack",
23
+ "LoongArch64Stack",
22
24
  "MIPSBEStack",
23
25
  "MIPSELStack",
24
26
  "MIPS64BEStack",
@@ -0,0 +1,26 @@
1
+ import typing
2
+
3
+ from .... import platforms
4
+ from . import stack
5
+
6
+
7
+ class LoongArchStack(stack.DescendingStack):
8
+ """A stack for a LoongArch CPU"""
9
+
10
+ def get_pointer(self) -> int:
11
+ return (self.address + self.size) - self.get_used()
12
+
13
+ def get_alignment(self) -> int:
14
+ return 4
15
+
16
+ @classmethod
17
+ def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
18
+ raise NotImplementedError("Stack initialization not implemented for MIPS64")
19
+
20
+
21
+ class LoongArch64Stack(LoongArchStack):
22
+ """A stack for a LoongArch 64-bit CPU"""
23
+
24
+ platform = platforms.Platform(
25
+ platforms.Architecture.LOONGARCH64, platforms.Byteorder.LITTLE
26
+ )