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
@@ -0,0 +1,759 @@
1
+ import abc
2
+ import enum
3
+ import struct
4
+ import typing
5
+
6
+ from ... import emulators, exceptions
7
+ from ...platforms import Byteorder, PlatformDef
8
+ from .model import Model
9
+
10
+
11
+ class ArgumentType(enum.Enum):
12
+ """C primitive data types for specifying function arguments.
13
+
14
+ The exact size of these types depends strongly on the ABI.
15
+ These specify the source-level signature;
16
+ the ABI-specific subclasses of CStdModel figure out how to decode them.
17
+ """
18
+
19
+ CHAR = "char"
20
+ UCHAR = "unsigned char"
21
+
22
+ SHORT = "short"
23
+ USHORT = "unsigned short"
24
+
25
+ INT = "int"
26
+ UINT = "unsigned int"
27
+
28
+ LONG = "long"
29
+ ULONG = "unsigned long"
30
+
31
+ POINTER = "pointer"
32
+
33
+ SIZE_T = "size_t"
34
+ SSIZE_T = "ssize_t"
35
+
36
+ LONGLONG = "long long"
37
+ ULONGLONG = "unsigned long long"
38
+
39
+ FLOAT = "float"
40
+ DOUBLE = "double"
41
+
42
+ VOID = "void"
43
+
44
+
45
+ signed_int_types = {
46
+ ArgumentType.INT,
47
+ ArgumentType.LONG,
48
+ ArgumentType.LONGLONG,
49
+ ArgumentType.SSIZE_T,
50
+ }
51
+
52
+
53
+ def add_argument(
54
+ i: int, kind: ArgumentType, model: typing.Union["CStdModel", "VariadicContext"]
55
+ ):
56
+ if kind in model._four_byte_types or (
57
+ kind == ArgumentType.FLOAT and model._soft_float
58
+ ):
59
+ # Four byte int type, or float on a system without separate FP arg regs
60
+ if model._int_reg_offset == len(model._four_byte_arg_regs):
61
+ # No room left in registers; use stack
62
+ model._on_stack.append(True)
63
+ model._arg_offset.append(model._stack_offset + model._init_stack_offset)
64
+ model._stack_offset += model._four_byte_stack_size
65
+ else:
66
+ # Registers left; use them
67
+ model._on_stack.append(False)
68
+ model._arg_offset.append(model._int_reg_offset)
69
+ model._int_reg_offset += 1
70
+ elif kind in model._eight_byte_types or (
71
+ kind == ArgumentType.DOUBLE and model._soft_float
72
+ ):
73
+ # Eight byte int type, or double on a system without separate FP arg regs
74
+ if model._int_reg_offset % model._eight_byte_reg_size != 0:
75
+ # Align argument register for eight-byte value
76
+ model._int_reg_offset += 1
77
+
78
+ if model._int_reg_offset == len(model._eight_byte_arg_regs):
79
+ # No room left in registers; use stack
80
+ if (
81
+ model._align_stack
82
+ and model._stack_offset % model._eight_byte_stack_size != 0
83
+ ):
84
+ # Stack out of alignment. Align it.
85
+ model._stack_offset += 4
86
+ model._on_stack.append(True)
87
+ model._arg_offset.append(model._stack_offset + model._init_stack_offset)
88
+ model._stack_offset += model._eight_byte_stack_size
89
+ else:
90
+ # Registers left; use them
91
+ model._on_stack.append(False)
92
+ model._arg_offset.append(model._int_reg_offset)
93
+ model._int_reg_offset += model._eight_byte_reg_size
94
+ elif kind == ArgumentType.FLOAT:
95
+ # Float type
96
+ if model._fp_reg_offset == len(model._float_arg_regs):
97
+ # No room left in registers; use stack
98
+ model._on_stack.append(True)
99
+ model._arg_offset.append(model._stack_offset + model._init_stack_offset)
100
+ model._stack_offset += model._float_stack_size
101
+ else:
102
+ # Registers left; use them
103
+ model._on_stack.append(False)
104
+ model._arg_offset.append(model._fp_reg_offset)
105
+ model._fp_reg_offset += 1
106
+ elif kind == ArgumentType.DOUBLE:
107
+ # Double type
108
+ if model._fp_reg_offset % model._double_reg_size != 0:
109
+ model._fp_reg_offset += 1
110
+
111
+ if model._fp_reg_offset == len(model._double_arg_regs):
112
+ # No room left in registers; use stack
113
+ if (
114
+ model._align_stack
115
+ and model._stack_offset % model._double_stack_size != 0
116
+ ):
117
+ model._stack_offset += 4
118
+ model._on_stack.append(True)
119
+ model._arg_offset.append(model._stack_offset + model._init_stack_offset)
120
+ model._stack_offset += model._double_stack_size
121
+ else:
122
+ # Registers left; use them
123
+ model._on_stack.append(False)
124
+ model._arg_offset.append(model._fp_reg_offset)
125
+ model._fp_reg_offset += model._double_reg_size
126
+ else:
127
+ raise exceptions.ConfigurationError(
128
+ f"{model.name} argument {i} has unknown type {kind}"
129
+ )
130
+
131
+
132
+ def get_argument(
133
+ model: typing.Union["CStdModel", "VariadicContext"],
134
+ index: int,
135
+ kind: ArgumentType,
136
+ emulator: emulators.Emulator,
137
+ ) -> typing.Union[int, float]:
138
+ # Get an argument out of a CStdModel or VariadicContext
139
+ sp = model.platdef.sp_register
140
+ on_stack = model._on_stack[index]
141
+ arg_offset = model._arg_offset[index]
142
+
143
+ if kind in model._four_byte_types:
144
+ # Four byte integer
145
+ if on_stack:
146
+ # Stored on the stack; read from memory
147
+ addr = emulator.read_register(sp) + arg_offset
148
+ data = emulator.read_memory(addr, model._four_byte_stack_size)
149
+ if model.platform.byteorder == Byteorder.BIG:
150
+ intval = int.from_bytes(data, "big")
151
+ else:
152
+ intval = int.from_bytes(data, "little")
153
+ else:
154
+ # Stored in a register
155
+ intval = emulator.read_register(model._four_byte_arg_regs[arg_offset])
156
+
157
+ # Handle integer signing and signedness
158
+ # SmallWorld registers are unsigned, so we'll need to convert.
159
+ # Some architectures zero-extend their integers, so we need to mask.
160
+ intval = intval & model._int_inv_mask
161
+ if kind in signed_int_types and (intval & model._int_sign_mask) != 0:
162
+ intval = (intval ^ model._int_inv_mask) + 1
163
+ intval *= -1
164
+ return intval
165
+
166
+ elif kind in model._eight_byte_types:
167
+ # Eight byte integer
168
+ if on_stack:
169
+ # Stored on the stack
170
+ addr = emulator.read_register(sp) + arg_offset
171
+ data = emulator.read_memory(addr, model._eight_byte_stack_size)
172
+ if model.platform.byteorder == Byteorder.BIG:
173
+ intval = int.from_bytes(data, "big")
174
+ else:
175
+ intval = int.from_bytes(data, "little")
176
+ elif model._eight_byte_reg_size == 2:
177
+ # Stored in a register pair
178
+ lo = emulator.read_register(model._eight_byte_arg_regs[arg_offset])
179
+ hi = emulator.read_register(model._eight_byte_arg_regs[arg_offset + 1])
180
+ if model.platform.byteorder == Byteorder.BIG:
181
+ tmp = lo
182
+ lo = hi
183
+ hi = tmp
184
+ intval = (hi << 32) | lo
185
+ else:
186
+ # Stored in a single register
187
+ intval = emulator.read_register(model._eight_byte_arg_regs[arg_offset])
188
+
189
+ # Handle signedness
190
+ # SmallWorld registers are unsigned, so we'll need to convert.
191
+ if kind in signed_int_types and (intval & model._long_long_sign_mask) != 0:
192
+ intval = (intval ^ model._long_long_inv_mask) + 1
193
+ intval *= -1
194
+ return intval
195
+ elif kind == ArgumentType.FLOAT:
196
+ # Four-byte float
197
+ if on_stack:
198
+ # Stored on the stack
199
+ addr = emulator.read_register(sp) + arg_offset
200
+ data = emulator.read_memory(addr, model._float_stack_size)
201
+ if model.platform.byteorder == Byteorder.BIG:
202
+ intval = int.from_bytes(data, "big")
203
+ else:
204
+ intval = int.from_bytes(data, "little")
205
+ elif model._soft_float:
206
+ # Soft-float ABI; treat as a four-byte int
207
+ intval = emulator.read_register(model._four_byte_arg_regs[arg_offset])
208
+ else:
209
+ # Hard-float ABI; fetch from FPU registers
210
+ intval = emulator.read_register(model._float_arg_regs[arg_offset])
211
+
212
+ # Unpack the bits into a Python float
213
+ # SmallWorld already did the work of converting endianness.
214
+ if model._floats_are_doubles:
215
+ # Some ABIs promote floats to doubles.
216
+ # And by "some ABIs", I mean PowerPC.
217
+ byteval = intval.to_bytes(8, "little")
218
+ (floatval,) = struct.unpack("<d", byteval)
219
+ else:
220
+ byteval = (intval & model._int_inv_mask).to_bytes(4, "little")
221
+ (floatval,) = struct.unpack("<f", byteval)
222
+ return floatval
223
+ elif kind == ArgumentType.DOUBLE:
224
+ # Eight-byte double float
225
+ if on_stack:
226
+ # Stored on the stack
227
+ addr = emulator.read_register(sp) + arg_offset
228
+ data = emulator.read_memory(addr, model._double_stack_size)
229
+ if model.platform.byteorder == Byteorder.BIG:
230
+ intval = int.from_bytes(data, "big")
231
+ else:
232
+ intval = int.from_bytes(data, "little")
233
+ else:
234
+ if model._soft_float:
235
+ # Soft-float ABI; treated as an eight-byte int
236
+ reg_array = model._eight_byte_arg_regs
237
+ n_regs = model._eight_byte_reg_size
238
+ else:
239
+ # Hard-float ABI; stored in FPU registers
240
+ reg_array = model._double_arg_regs
241
+ n_regs = model._double_reg_size
242
+
243
+ if n_regs == 2:
244
+ # Register pair. Possible for both soft and hard floats.
245
+ lo = emulator.read_register(reg_array[arg_offset])
246
+ hi = emulator.read_register(reg_array[arg_offset + 1])
247
+ if model.platform.byteorder == Byteorder.BIG:
248
+ tmp = lo
249
+ lo = hi
250
+ hi = tmp
251
+ intval = (hi << 32) | lo
252
+ else:
253
+ # Single register
254
+ intval = emulator.read_register(reg_array[arg_offset])
255
+
256
+ # Convert bits into Python float
257
+ # SmallWorld already did the work of converting endianness.
258
+ byteval = intval.to_bytes(8, "little")
259
+ (floatval,) = struct.unpack("<d", byteval)
260
+ return floatval
261
+ else:
262
+ raise exceptions.ConfigurationError(
263
+ f"{model.name} argument {index} has unknown type {kind}"
264
+ )
265
+
266
+
267
+ class CStdModel(Model):
268
+ """Base class for C standard function models
269
+
270
+
271
+ Regardless of which version of a library you use,
272
+ all "true" C functions will use the same interface
273
+ defined by the ABI.
274
+ (There are exceptions, such as thunks and internal functions
275
+ never intended for human eyes)
276
+
277
+ This abstracts away the ABI-specific operations
278
+ performed by a function, namely getting args and returning vals.
279
+
280
+ This also includes a parameterizable calling convention model.
281
+ Every calling convention I've seen fits into a kind
282
+ of Grand Unifying Theory. They all pass a certain
283
+ number of arguments via registers before switching to stack,
284
+ and handle different-sized integers or floats
285
+ in a few standard ways.
286
+
287
+ It was way easier to figure out this theory and write one model
288
+ than to maintain eleven-plus separate models.
289
+ This may break for particularly unusual architectures,
290
+ or very strange ABIs. For living architectures
291
+ with Debian support (sorry, hppa), it works.
292
+ """
293
+
294
+ # Flag indicating this model is imprecise.
295
+ #
296
+ # Most models are assumed to be approximations,
297
+ # but this model definitely doesn't capture
298
+ # a critical behavior.
299
+ #
300
+ # By default, these models should raise an exception if called.
301
+ # The user can accept the risk and run a placeholde version
302
+ # by setting the attribute "allow_imprecise" to True.
303
+ #
304
+ # Authors probably shouldn't rely on this flag
305
+ # to mark truly-unimplemented models;
306
+ # just raise an exception yourself.
307
+ imprecise = False
308
+
309
+ @property
310
+ @abc.abstractmethod
311
+ def argument_types(self) -> typing.List[ArgumentType]:
312
+ """List of argument types for this function
313
+
314
+ NOTE: Don't include variadics.
315
+ """
316
+ raise NotImplementedError()
317
+
318
+ @property
319
+ @abc.abstractmethod
320
+ def return_type(self) -> ArgumentType:
321
+ """Return type for this function"""
322
+ raise NotImplementedError()
323
+
324
+ def __init__(self, address: int):
325
+ super().__init__(address)
326
+
327
+ self.platdef = PlatformDef.for_platform(self.platform)
328
+
329
+ # Set this to True to bypass the "imprecise" flag.
330
+ self.allow_imprecise = False
331
+
332
+ self._int_reg_offset = 0
333
+ self._fp_reg_offset = 0
334
+ self._stack_offset = 0
335
+
336
+ self._on_stack: typing.List[bool] = list()
337
+ self._arg_offset: typing.List[int] = list()
338
+
339
+ for i in range(0, len(self.argument_types)):
340
+ t = self.argument_types[i]
341
+ add_argument(i, t, self)
342
+
343
+ def model(self, emulator: emulators.Emulator):
344
+ if self.imprecise and not self.allow_imprecise:
345
+ raise exceptions.ConfigurationError(
346
+ f"Invoked model for {self.name}, which is imprecise"
347
+ )
348
+
349
+ @abc.abstractmethod
350
+ def _return_4_byte(self, emulator: emulators.Emulator, val: int) -> None:
351
+ """Return a four-byte type"""
352
+ raise NotImplementedError()
353
+
354
+ @abc.abstractmethod
355
+ def _return_8_byte(self, emulator: emulators.Emulator, val: int) -> None:
356
+ """Return an eight-byte type"""
357
+ raise NotImplementedError()
358
+
359
+ @abc.abstractmethod
360
+ def _return_float(self, emulator: emulators.Emulator, val: float) -> None:
361
+ """Return a float"""
362
+ raise NotImplementedError()
363
+
364
+ @abc.abstractmethod
365
+ def _return_double(self, emulator: emulators.Emulator, val: float) -> None:
366
+ """Return a double"""
367
+ raise NotImplementedError()
368
+
369
+ def get_arg1(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
370
+ """Fetch the first argument from the emulator"""
371
+ return get_argument(self, 0, self.argument_types[0], emulator)
372
+
373
+ def get_arg2(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
374
+ """Fetch the second argument from the emulator"""
375
+ return get_argument(self, 1, self.argument_types[1], emulator)
376
+
377
+ def get_arg3(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
378
+ """Fetch the first argument from the emulator"""
379
+ return get_argument(self, 2, self.argument_types[2], emulator)
380
+
381
+ def get_arg4(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
382
+ """Fetch the first argument from the emulator"""
383
+ return get_argument(self, 3, self.argument_types[3], emulator)
384
+
385
+ def get_arg5(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
386
+ """Fetch the first argument from the emulator"""
387
+ return get_argument(self, 4, self.argument_types[4], emulator)
388
+
389
+ def get_arg6(self, emulator: emulators.Emulator) -> typing.Union[int, float]:
390
+ """Fetch the first argument from the emulator"""
391
+ return get_argument(self, 5, self.argument_types[5], emulator)
392
+
393
+ def get_varargs(self) -> "VariadicContext":
394
+ """Get a variadic argument context to fetch varargs
395
+
396
+ Also necessary to handle more than six arguments.
397
+ """
398
+ return VariadicContext(self)
399
+
400
+ def set_return_value(
401
+ self, emulator: emulators.Emulator, val: typing.Union[int, float]
402
+ ) -> None:
403
+ """Return according to the appropriate return type"""
404
+ if self.return_type == ArgumentType.VOID:
405
+ # We're void. You can't return from void.
406
+ raise exceptions.ConfigurationError(
407
+ f"{self.name} returning from void function"
408
+ )
409
+
410
+ if self.return_type == ArgumentType.FLOAT:
411
+ # We're a float.
412
+ if not isinstance(val, float):
413
+ raise exceptions.ConfigurationError(
414
+ f"{self.name} trying to return {type(val)} as a float"
415
+ )
416
+ self._return_float(emulator, val)
417
+ return
418
+
419
+ if self.return_type == ArgumentType.DOUBLE:
420
+ # We're a double
421
+ if not isinstance(val, float):
422
+ raise exceptions.ConfigurationError(
423
+ f"{self.name} trying to return {type(val)} as a double"
424
+ )
425
+ self._return_double(emulator, val)
426
+ return
427
+
428
+ # All other types are integral
429
+ if not isinstance(val, int):
430
+ raise exceptions.ConfigurationError(
431
+ f"{self.name} trying to return {type(val)} as an integral type"
432
+ )
433
+
434
+ if val < 0:
435
+ # Negative value; need to find 2s-compliment if it's an int
436
+ val *= -1
437
+ if self.return_type in self._four_byte_types:
438
+ val = ((val ^ self._int_inv_mask) + 1) & self._int_inv_mask
439
+ elif self.return_type in self._eight_byte_types:
440
+ val = ((val ^ self._long_long_inv_mask) + 1) & self._long_long_inv_mask
441
+ elif (
442
+ self.return_type == ArgumentType.FLOAT
443
+ or self.return_type == ArgumentType.DOUBLE
444
+ ):
445
+ # Floating-point type; encoding will take care of this.
446
+ pass
447
+ else:
448
+ # Unsigned type; why are you returning a negative?
449
+ raise exceptions.ConfigurationError(
450
+ f"{self.name} tried to return a signed value"
451
+ )
452
+
453
+ # Delegate return to handler
454
+ if self.return_type in self._four_byte_types:
455
+ self._return_4_byte(emulator, val)
456
+
457
+ elif self.return_type in self._eight_byte_types:
458
+ self._return_8_byte(emulator, val)
459
+
460
+ else:
461
+ raise exceptions.ConfigurationError(
462
+ f"{self.name} returning unhandled type {self.return_type}"
463
+ )
464
+
465
+ def read_integer(
466
+ self, address: int, kind: ArgumentType, emulator: emulators.Emulator
467
+ ) -> int:
468
+ """Read an integer out of memory based on type
469
+
470
+ Arguments:
471
+ address: The address to read from
472
+ kind: The ArgumentType to read
473
+ emulator: The emulator to read from
474
+ """
475
+ if kind in (ArgumentType.CHAR, ArgumentType.UCHAR):
476
+ width = 1
477
+ elif kind in (ArgumentType.SHORT, ArgumentType.USHORT):
478
+ width = 2
479
+ elif kind in (ArgumentType.INT, ArgumentType.UINT):
480
+ width = 4
481
+ elif kind in (ArgumentType.LONG, ArgumentType.ULONG, ArgumentType.POINTER):
482
+ width = 4 if ArgumentType.LONG in self._four_byte_types else 8
483
+ elif kind in (ArgumentType.LONGLONG, ArgumentType.ULONGLONG):
484
+ width = 8
485
+
486
+ byteval = emulator.read_memory(address, width)
487
+
488
+ if self.platform.byteorder == Byteorder.LITTLE:
489
+ return int.from_bytes(byteval, "little")
490
+ else:
491
+ return int.from_bytes(byteval, "big")
492
+
493
+ def write_integer(
494
+ self,
495
+ address: int,
496
+ intval: int,
497
+ kind: ArgumentType,
498
+ emulator: emulators.Emulator,
499
+ ) -> None:
500
+ """Write an integer based on type
501
+
502
+ Note that this will handle converting signed to bytes.
503
+
504
+ Arguments:
505
+ address: The address to write to
506
+ intval: The integer value to write
507
+ kind: The ArgumentType to write
508
+ emulator: The emulator to write to
509
+ """
510
+ if intval < 0:
511
+ intval *= -1
512
+ intval = (intval ^ self._long_long_inv_mask) + 1
513
+
514
+ if kind in (ArgumentType.CHAR, ArgumentType.UCHAR):
515
+ intval &= self._char_inv_mask
516
+ width = 1
517
+ elif kind in (ArgumentType.SHORT, ArgumentType.USHORT):
518
+ intval &= self._short_inv_mask
519
+ width = 2
520
+ elif kind in (ArgumentType.INT, ArgumentType.UINT):
521
+ intval &= self._int_inv_mask
522
+ width = 4
523
+ elif kind in (ArgumentType.LONG, ArgumentType.ULONG, ArgumentType.POINTER):
524
+ intval &= self._long_inv_mask
525
+ width = 4 if ArgumentType.LONG in self._four_byte_types else 8
526
+ elif kind in (ArgumentType.LONGLONG, ArgumentType.ULONGLONG):
527
+ intval &= self._long_long_inv_mask
528
+ width = 8
529
+
530
+ if self.platform.byteorder == Byteorder.LITTLE:
531
+ byteval = intval.to_bytes(width, "little")
532
+ else:
533
+ byteval = intval.to_bytes(width, "big")
534
+
535
+ emulator.write_memory(address, byteval)
536
+
537
+ # *** Integer arithmetic constants ***
538
+ #
539
+ # Generalized bitmasks for specific types,
540
+ # determined by their size on this ABI.
541
+
542
+ _char_sign_mask: int = 0x80
543
+ _char_inv_mask: int = 0xFF
544
+
545
+ _short_sign_mask: int = 0x8000
546
+ _short_inv_mask: int = 0xFFFF
547
+
548
+ @property
549
+ @abc.abstractmethod
550
+ def _int_sign_mask(self) -> int:
551
+ # Bitmask covering the sign bit of an int
552
+ raise NotImplementedError()
553
+
554
+ @property
555
+ @abc.abstractmethod
556
+ def _int_inv_mask(self) -> int:
557
+ # Bitmask covering all bits of an int
558
+ raise NotImplementedError()
559
+
560
+ @property
561
+ @abc.abstractmethod
562
+ def _long_sign_mask(self) -> int:
563
+ # Bitmask covering the sign bit of a long
564
+ raise NotImplementedError()
565
+
566
+ @property
567
+ @abc.abstractmethod
568
+ def _long_long_inv_mask(self) -> int:
569
+ # Bitmask covering all bits of a lon
570
+ raise NotImplementedError()
571
+
572
+ @property
573
+ @abc.abstractmethod
574
+ def _long_long_sign_mask(self) -> int:
575
+ # Bitmask covering the sign bit of a long long
576
+ raise NotImplementedError()
577
+
578
+ @property
579
+ @abc.abstractmethod
580
+ def _long_inv_mask(self) -> int:
581
+ # Bitmask covering all bits of a long long
582
+ raise NotImplementedError()
583
+
584
+ # Mask for sign-extending 32-bit numbers to 64-bit.
585
+ _int_signext_mask = 0xFFFFFFFF00000000
586
+
587
+ # *** Configuration Constants ***
588
+ #
589
+ # It turns out most ABIs follow a generalizable pattern
590
+ # when it comes to passing arguments.
591
+ #
592
+ # The following static fields are the configurations for this pattern.
593
+ # The actual implementation for adding an argument to the signature,
594
+ # and fetching an argument from the emulator
595
+ # are in the functions `add_argument` and `get_argument`.
596
+ #
597
+ # These are separate because they're used by fixed and variadic calls,
598
+ # which are handled separately.
599
+
600
+ @property
601
+ @abc.abstractmethod
602
+ def _four_byte_types(self) -> typing.Set[ArgumentType]:
603
+ """Types that are four bytes in this ABI."""
604
+ raise NotImplementedError()
605
+
606
+ @property
607
+ @abc.abstractmethod
608
+ def _eight_byte_types(self) -> typing.Set[ArgumentType]:
609
+ """Types that are eight bytes in this ABI."""
610
+ raise NotImplementedError()
611
+
612
+ @property
613
+ @abc.abstractmethod
614
+ def _four_byte_arg_regs(self) -> typing.List[str]:
615
+ """Registers for four-byte arguments"""
616
+ raise NotImplementedError()
617
+
618
+ @property
619
+ @abc.abstractmethod
620
+ def _eight_byte_arg_regs(self) -> typing.List[str]:
621
+ """Registers for eight-byte arguments"""
622
+ raise NotImplementedError()
623
+
624
+ @property
625
+ @abc.abstractmethod
626
+ def _soft_float(self) -> bool:
627
+ """Use int regs for fp arguments"""
628
+ raise NotImplementedError()
629
+
630
+ @property
631
+ @abc.abstractmethod
632
+ def _variadic_soft_float(self) -> bool:
633
+ """Use int regs for fp arguments for variadic args"""
634
+ raise NotImplementedError()
635
+
636
+ @property
637
+ @abc.abstractmethod
638
+ def _floats_are_doubles(self) -> bool:
639
+ """Floats are actually stored as doubles"""
640
+ raise NotImplementedError()
641
+
642
+ @property
643
+ @abc.abstractmethod
644
+ def _float_arg_regs(self) -> typing.List[str]:
645
+ """Registers for float arguments"""
646
+ raise NotImplementedError()
647
+
648
+ @property
649
+ @abc.abstractmethod
650
+ def _double_arg_regs(self) -> typing.List[str]:
651
+ """Registers for double arguments"""
652
+ raise NotImplementedError()
653
+
654
+ @property
655
+ @abc.abstractmethod
656
+ def _init_stack_offset(self) -> int:
657
+ """Initial offset for stack arguments"""
658
+ raise NotImplementedError()
659
+
660
+ @property
661
+ @abc.abstractmethod
662
+ def _align_stack(self) -> bool:
663
+ """Align stack for eight-byte values"""
664
+ raise NotImplementedError()
665
+
666
+ @property
667
+ @abc.abstractmethod
668
+ def _eight_byte_reg_size(self) -> int:
669
+ """Number of registers required for an eight-byte value"""
670
+ raise NotImplementedError()
671
+
672
+ @property
673
+ @abc.abstractmethod
674
+ def _double_reg_size(self) -> int:
675
+ """Number of registers required for a double value"""
676
+ raise NotImplementedError()
677
+
678
+ @property
679
+ @abc.abstractmethod
680
+ def _four_byte_stack_size(self) -> int:
681
+ """Size of a four-byte argument on the stack. Not always four bytes"""
682
+ raise NotImplementedError()
683
+
684
+ @property
685
+ @abc.abstractmethod
686
+ def _eight_byte_stack_size(self) -> int:
687
+ """Size of an eight-byte argument on the stack."""
688
+ raise NotImplementedError()
689
+
690
+ @property
691
+ @abc.abstractmethod
692
+ def _float_stack_size(self) -> int:
693
+ """Size of a float on the stack"""
694
+ raise NotImplementedError()
695
+
696
+ @property
697
+ def _double_stack_size(self) -> int:
698
+ """Size of a double on the stack"""
699
+ raise NotImplementedError()
700
+
701
+
702
+ class VariadicContext:
703
+ """Context for extracting variadic arguments
704
+
705
+ Variadic functions extend the argument list at runtime.
706
+ Handling this requires dynamically updating the
707
+ list of arguments. I'd rather do this on a throw-away object
708
+ than on a Model object that will have to reset itself
709
+ for multiple invocations.
710
+
711
+ """
712
+
713
+ def __init__(self, parent: CStdModel) -> None:
714
+ self.name = parent.name
715
+ self.platform = parent.platform
716
+ self.platdef = parent.platdef
717
+
718
+ # Copy the calling convention specification from the parent
719
+ # It's this, or slow the interpreter down by using properties.
720
+ self._int_sign_mask = parent._int_sign_mask
721
+ self._int_inv_mask = parent._int_inv_mask
722
+ self._long_sign_mask = parent._long_sign_mask
723
+ self._long_inv_mask = parent._long_inv_mask
724
+ self._long_long_sign_mask = parent._long_long_sign_mask
725
+ self._long_long_inv_mask = parent._long_long_inv_mask
726
+
727
+ self._four_byte_types = parent._four_byte_types
728
+ self._eight_byte_types = parent._eight_byte_types
729
+ self._four_byte_arg_regs = parent._four_byte_arg_regs
730
+ self._eight_byte_arg_regs = parent._eight_byte_arg_regs
731
+ self._soft_float = parent._soft_float or parent._variadic_soft_float
732
+ self._floats_are_doubles = parent._floats_are_doubles
733
+ self._float_arg_regs = parent._float_arg_regs
734
+ self._double_arg_regs = parent._double_arg_regs
735
+ self._init_stack_offset = parent._init_stack_offset
736
+ self._align_stack = parent._align_stack
737
+ self._eight_byte_reg_size = parent._eight_byte_reg_size
738
+ self._double_reg_size = parent._double_reg_size
739
+ self._four_byte_stack_size = parent._four_byte_stack_size
740
+ self._eight_byte_stack_size = parent._eight_byte_stack_size
741
+ self._float_stack_size = parent._float_stack_size
742
+ self._double_stack_size = parent._double_stack_size
743
+
744
+ # Copy the parent's current argument state
745
+ self._int_reg_offset = parent._int_reg_offset
746
+ self._fp_reg_offset = parent._fp_reg_offset
747
+ self._stack_offset = parent._stack_offset
748
+
749
+ self._on_stack = parent._on_stack.copy()
750
+ self._arg_offset = parent._arg_offset.copy()
751
+
752
+ def get_next_argument(
753
+ self, kind: ArgumentType, emulator: emulators.Emulator
754
+ ) -> typing.Union[int, float]:
755
+ """Get the next argument of an assumed type"""
756
+ index = len(self._on_stack)
757
+
758
+ add_argument(index, kind, self)
759
+ return get_argument(self, index, kind, emulator)