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,1305 @@
1
+ import random
2
+ import string
3
+ import typing
4
+
5
+ from .... import emulators, exceptions
6
+ from ....platforms import Byteorder
7
+ from ..cstd import ArgumentType, CStdModel
8
+ from ..filedesc import FDIOError, FileDescriptorManager
9
+ from .fmt_print import parse_printf_format
10
+ from .fmt_scan import FileIntake, StringIntake, handle_scanf_format
11
+ from .utils import _emu_strlen
12
+
13
+
14
+ class StdioModel(CStdModel):
15
+ def __init__(self, address: int):
16
+ super().__init__(address)
17
+ self._fdmgr = FileDescriptorManager.for_platform(self.platform, self.abi)
18
+
19
+ def _parse_mode(self, mode: str) -> typing.Tuple[bool, bool, bool, bool, bool]:
20
+ readable = False
21
+ writable = False
22
+ create = False
23
+ truncate = False
24
+ append = True
25
+ if mode in ("r", "rb"):
26
+ # - Open for reading
27
+ # - Fails if doesn't exist
28
+ # - Cursor starts at zero
29
+ readable = True
30
+ elif mode in ("r+", "r+b"):
31
+ # - Open for reading and writing
32
+ # - Fails if doesn't exist
33
+ # - Cursor starts at zero
34
+ readable = True
35
+ writable = True
36
+ elif mode in ("w", "wb"):
37
+ # - Open for writing
38
+ # - Creates if doesn't exist
39
+ # - Truncates if exists
40
+ # - Cursor starts at zero
41
+ writable = True
42
+ create = True
43
+ truncate = True
44
+ elif mode in ("w+", "w+b"):
45
+ # - Open for reading and writing
46
+ # - Creates if doesn't exist
47
+ # - Truncates if exists
48
+ # - Cursor starts at zero
49
+ readable = True
50
+ writable = True
51
+ create = True
52
+ truncate = True
53
+ elif mode in ("a", "ab"):
54
+ # - Open for writing
55
+ # - Creates if doesn't exist
56
+ # - Cursor starts at end
57
+ writable = True
58
+ create = True
59
+ append = True
60
+ elif mode in ("a+", "a+b"):
61
+ # - Open for reading and writing
62
+ # - Creates if doesn't exist
63
+ # - Start is unspecified; glibc does the beginning
64
+ readable = True
65
+ writable = True
66
+ create = True
67
+ else:
68
+ raise FDIOError(f"Unknown mode {mode}")
69
+
70
+ return (readable, writable, create, truncate, append)
71
+
72
+ def _generate_tmpnam(self):
73
+ # TODO: Doesn't actually test uniqueness
74
+ search = string.ascii_letters + "0123456789"
75
+
76
+ out = "/tmp/file"
77
+ for i in range(0, 6):
78
+ out += search[random.randint(0, len(search) - 1)]
79
+
80
+ return out
81
+
82
+
83
+ class Fclose(StdioModel):
84
+ name = "fclose"
85
+
86
+ # int fclose(FILE *file);
87
+ argument_types = [ArgumentType.POINTER]
88
+ return_type = ArgumentType.INT
89
+
90
+ def model(self, emulator: emulators.Emulator) -> None:
91
+ super().model(emulator)
92
+ ptr = self.get_arg1(emulator)
93
+
94
+ assert isinstance(ptr, int)
95
+
96
+ try:
97
+ fd = self._fdmgr.filestar_to_fd(ptr)
98
+ self._fdmgr.close(fd)
99
+ self.set_return_value(emulator, 0)
100
+ except FDIOError:
101
+ self.set_return_value(emulator, -1)
102
+
103
+
104
+ class Feof(StdioModel):
105
+ name = "feof"
106
+
107
+ # int feof(FILE *file);
108
+ argument_types = [ArgumentType.POINTER]
109
+ return_type = ArgumentType.INT
110
+
111
+ def model(self, emulator: emulators.Emulator) -> None:
112
+ super().model(emulator)
113
+
114
+ filestar = self.get_arg1(emulator)
115
+
116
+ assert isinstance(filestar, int)
117
+
118
+ try:
119
+ fd = self._fdmgr.filestar_to_fd(filestar)
120
+ file = self._fdmgr.get(fd)
121
+ except FDIOError:
122
+ print(f"Failed looking up filestar {filestar:x}")
123
+ self.set_return_value(emulator, -1)
124
+ return
125
+
126
+ print(f"EOF: {file.eof}")
127
+ self.set_return_value(emulator, 1 if file.eof else 0)
128
+
129
+
130
+ class Ferror(StdioModel):
131
+ name = "ferror"
132
+
133
+ # int ferror(FILE *file);
134
+ argument_types = [ArgumentType.POINTER]
135
+ return_type = ArgumentType.INT
136
+
137
+ def model(self, emulator: emulators.Emulator) -> None:
138
+ super().model(emulator)
139
+
140
+ # We never have errors.
141
+ self.set_return_value(emulator, 0)
142
+
143
+
144
+ class Clearerr(StdioModel):
145
+ name = "clearerr"
146
+
147
+ # void clearerr(FILE *file);
148
+ argument_types = [ArgumentType.POINTER]
149
+ return_type = ArgumentType.VOID
150
+
151
+ def model(self, emulator: emulators.Emulator) -> None:
152
+ super().model(emulator)
153
+
154
+ filestar = self.get_arg1(emulator)
155
+
156
+ assert isinstance(filestar, int)
157
+
158
+ try:
159
+ fd = self._fdmgr.filestar_to_fd(filestar)
160
+ file = self._fdmgr.get(fd)
161
+ except FDIOError:
162
+ print(f"Failed looking up filestar {filestar:x}")
163
+ self.set_return_value(emulator, -1)
164
+ return
165
+
166
+ file.eof = False
167
+
168
+
169
+ class Fflush(StdioModel):
170
+ name = "fflush"
171
+
172
+ # int fflush(FILE *file);
173
+ argument_types = [ArgumentType.POINTER]
174
+ return_type = ArgumentType.INT
175
+
176
+ def model(self, emulator: emulators.Emulator) -> None:
177
+ super().model(emulator)
178
+ # TODO: If you want to model something more interesting here, we can talk.
179
+ self.set_return_value(emulator, 0)
180
+
181
+
182
+ class Fgetc(StdioModel):
183
+ name = "fgetc"
184
+
185
+ # int fgetc(FILE *file);
186
+ argument_types = [ArgumentType.POINTER]
187
+ return_type = ArgumentType.INT
188
+
189
+ def model(self, emulator: emulators.Emulator) -> None:
190
+ super().model(emulator)
191
+
192
+ filestar = self.get_arg1(emulator)
193
+
194
+ assert isinstance(filestar, int)
195
+
196
+ try:
197
+ fd = self._fdmgr.filestar_to_fd(filestar)
198
+ file = self._fdmgr.get(fd)
199
+ except FDIOError:
200
+ print(f"Failed looking up filestar {filestar:x}")
201
+ self.set_return_value(emulator, -1)
202
+ return
203
+
204
+ try:
205
+ data = file.read(1, ungetc=True)
206
+ except Exception as e:
207
+ print(f"Failed reading from {file.name}: {e}")
208
+ raise e
209
+
210
+ print(f"Returning {data[0]:x}")
211
+ self.set_return_value(emulator, data[0])
212
+
213
+
214
+ class Fgets(StdioModel):
215
+ name = "fgets"
216
+
217
+ # char *fgets(char *dst, size_t size, FILE *file);
218
+ argument_types = [ArgumentType.POINTER, ArgumentType.SIZE_T, ArgumentType.POINTER]
219
+ return_type = ArgumentType.POINTER
220
+
221
+ def model(self, emulator: emulators.Emulator) -> None:
222
+ super().model(emulator)
223
+
224
+ dst = self.get_arg1(emulator)
225
+ size = self.get_arg2(emulator)
226
+ filestar = self.get_arg3(emulator)
227
+
228
+ assert isinstance(dst, int)
229
+ assert isinstance(size, int)
230
+ assert isinstance(filestar, int)
231
+
232
+ try:
233
+ fd = self._fdmgr.filestar_to_fd(filestar)
234
+ file = self._fdmgr.get(fd)
235
+ except FDIOError:
236
+ self.set_return_value(emulator, 0)
237
+ return
238
+
239
+ data = file.read_string(size)
240
+ emulator.write_memory(dst, data)
241
+ self.set_return_value(emulator, dst)
242
+
243
+
244
+ class Fopen(StdioModel):
245
+ name = "fopen"
246
+
247
+ # FILE *fopen(const char *path, const char *mode);
248
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
249
+ return_type = ArgumentType.POINTER
250
+
251
+ def model(self, emulator: emulators.Emulator) -> None:
252
+ super().model(emulator)
253
+ ptr1 = self.get_arg1(emulator)
254
+ ptr2 = self.get_arg2(emulator)
255
+
256
+ assert isinstance(ptr1, int)
257
+ assert isinstance(ptr2, int)
258
+
259
+ len1 = _emu_strlen(emulator, ptr1)
260
+ len2 = _emu_strlen(emulator, ptr2)
261
+
262
+ bytes1 = emulator.read_memory(ptr1, len1)
263
+ bytes2 = emulator.read_memory(ptr2, len2)
264
+
265
+ filepath = bytes1.decode("utf-8")
266
+ filemode = bytes2.decode("utf-8")
267
+
268
+ # FIXME: Not all files are seekable.
269
+ # For now, assume this one is.
270
+ seekable = True
271
+
272
+ try:
273
+ readable, writable, create, truncate, append = self._parse_mode(filemode)
274
+ fd = self._fdmgr.open(
275
+ filepath,
276
+ readable=readable,
277
+ writable=writable,
278
+ create=create,
279
+ truncate=truncate,
280
+ append=append,
281
+ seekable=seekable,
282
+ )
283
+ except FDIOError:
284
+ self.set_return_value(emulator, 0)
285
+ return
286
+
287
+ filestar = self._fdmgr.fd_to_filestar(fd)
288
+ self.set_return_value(emulator, filestar)
289
+
290
+
291
+ class Freopen(StdioModel):
292
+ name = "freopen"
293
+
294
+ # FILE *freopen(const char *filename, const char *mode, FILE *stream);
295
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
296
+ return_type = ArgumentType.POINTER
297
+
298
+ def model(self, emulator: emulators.Emulator) -> None:
299
+ super().model(emulator)
300
+
301
+ name = self.get_arg1(emulator)
302
+ mode = self.get_arg2(emulator)
303
+ filestar = self.get_arg3(emulator)
304
+
305
+ assert isinstance(name, int)
306
+ assert isinstance(mode, int)
307
+ assert isinstance(filestar, int)
308
+
309
+ len2 = _emu_strlen(emulator, mode)
310
+
311
+ bytes2 = emulator.read_memory(mode, len2)
312
+
313
+ filemode = bytes2.decode("utf-8")
314
+
315
+ # FIXME: Not all files are seekable.
316
+ # For now, assume this one is.
317
+ seekable = True
318
+
319
+ # Reset the access mode on the file
320
+ try:
321
+ fd = self._fdmgr.filestar_to_fd(filestar)
322
+ file = self._fdmgr.get(fd)
323
+ readable, writable, _, _, _ = self._parse_mode(filemode)
324
+ except FDIOError:
325
+ self.set_return_value(emulator, 0)
326
+ return
327
+
328
+ file.readable = readable
329
+ file.writable = writable
330
+ file.seekable = seekable
331
+
332
+ # Redirect the file if name is not NULL
333
+ if name != 0:
334
+ len1 = _emu_strlen(emulator, name)
335
+ bytes1 = emulator.read_memory(name, len1)
336
+ filepath = bytes1.decode("utf-8")
337
+
338
+ file.name = filepath
339
+
340
+ self.set_return_value(emulator, filestar)
341
+
342
+
343
+ class Fprintf(StdioModel):
344
+ name = "fprintf"
345
+
346
+ # int fprintf(FILE *file, const char *fmt, ...);
347
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
348
+ return_type = ArgumentType.INT
349
+
350
+ def model(self, emulator: emulators.Emulator) -> None:
351
+ super().model(emulator)
352
+
353
+ filestar = self.get_arg1(emulator)
354
+ fmt_addr = self.get_arg2(emulator)
355
+
356
+ assert isinstance(fmt_addr, int)
357
+
358
+ fmt_len = _emu_strlen(emulator, fmt_addr)
359
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
360
+ fmt = fmt_bytes.decode("utf-8")
361
+
362
+ output = parse_printf_format(self, fmt, emulator)
363
+ output_bytes = output.encode("utf-8")
364
+
365
+ try:
366
+ fd = self._fdmgr.filestar_to_fd(filestar)
367
+ file = self._fdmgr.get(fd)
368
+ except FDIOError:
369
+ self.set_return_value(emulator, -1)
370
+ return
371
+
372
+ file.write(output_bytes)
373
+
374
+ self.set_return_value(emulator, len(output_bytes))
375
+
376
+
377
+ class Fputc(StdioModel):
378
+ name = "fputc"
379
+
380
+ # int fputc(int c, FILE *file);
381
+ argument_types = [ArgumentType.INT, ArgumentType.POINTER]
382
+ return_type = ArgumentType.INT
383
+
384
+ def model(self, emulator: emulators.Emulator) -> None:
385
+ super().model(emulator)
386
+
387
+ char = self.get_arg1(emulator)
388
+ filestar = self.get_arg2(emulator)
389
+
390
+ assert isinstance(char, int)
391
+ assert isinstance(filestar, int)
392
+
393
+ try:
394
+ fd = self._fdmgr.filestar_to_fd(filestar)
395
+ file = self._fdmgr.get(fd)
396
+ except FDIOError:
397
+ self.set_return_value(emulator, -1)
398
+ return
399
+
400
+ file.write(bytes([char]))
401
+
402
+ self.set_return_value(emulator, char)
403
+
404
+
405
+ class Fputs(StdioModel):
406
+ name = "fputs"
407
+
408
+ # int fputs(const char *str, FILE *file);
409
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
410
+ return_type = ArgumentType.INT
411
+
412
+ def model(self, emulator: emulators.Emulator) -> None:
413
+ super().model(emulator)
414
+
415
+ ptr = self.get_arg1(emulator)
416
+ filestar = self.get_arg2(emulator)
417
+
418
+ assert isinstance(ptr, int)
419
+ assert isinstance(filestar, int)
420
+
421
+ strlen = _emu_strlen(emulator, ptr)
422
+ strbytes = emulator.read_memory(ptr, strlen)
423
+
424
+ try:
425
+ fd = self._fdmgr.filestar_to_fd(filestar)
426
+ file = self._fdmgr.get(fd)
427
+ except FDIOError:
428
+ self.set_return_value(emulator, -1)
429
+ return
430
+
431
+ file.write(strbytes)
432
+
433
+ self.set_return_value(emulator, 0)
434
+
435
+
436
+ class Fread(StdioModel):
437
+ name = "fread"
438
+
439
+ # size_t fread(void *dst, size_t size, size_t amt, FILE *file);
440
+ argument_types = [
441
+ ArgumentType.POINTER,
442
+ ArgumentType.SIZE_T,
443
+ ArgumentType.SIZE_T,
444
+ ArgumentType.POINTER,
445
+ ]
446
+ return_type = ArgumentType.SIZE_T
447
+
448
+ def model(self, emulator: emulators.Emulator) -> None:
449
+ super().model(emulator)
450
+
451
+ dst = self.get_arg1(emulator)
452
+ size = self.get_arg2(emulator)
453
+ amt = self.get_arg3(emulator)
454
+ filestar = self.get_arg4(emulator)
455
+
456
+ assert isinstance(dst, int)
457
+ assert isinstance(size, int)
458
+ assert isinstance(amt, int)
459
+ assert isinstance(filestar, int)
460
+
461
+ try:
462
+ fd = self._fdmgr.filestar_to_fd(filestar)
463
+ file = self._fdmgr.get(fd)
464
+ except FDIOError:
465
+ self.set_return_value(emulator, -1)
466
+ return
467
+
468
+ i = 0
469
+ for i in range(0, amt):
470
+ data = file.read(size)
471
+ if len(data) != size:
472
+ file.cursor -= len(data)
473
+ break
474
+
475
+ emulator.write_memory(dst, data)
476
+ dst += size
477
+
478
+ self.set_return_value(emulator, i)
479
+
480
+
481
+ class Fscanf(StdioModel):
482
+ name = "fscanf"
483
+
484
+ # int fscanf(FILE *, const char *fmt, ...);
485
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
486
+ return_type = ArgumentType.INT
487
+
488
+ def model(self, emulator: emulators.Emulator) -> None:
489
+ super().model(emulator)
490
+
491
+ filestar = self.get_arg1(emulator)
492
+ fmt_addr = self.get_arg2(emulator)
493
+
494
+ assert isinstance(filestar, int)
495
+ assert isinstance(fmt_addr, int)
496
+
497
+ fmt_len = _emu_strlen(emulator, fmt_addr)
498
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
499
+ fmt = fmt_bytes.decode("utf-8")
500
+
501
+ try:
502
+ fd = self._fdmgr.filestar_to_fd(filestar)
503
+ file = self._fdmgr.get(fd)
504
+ except FDIOError:
505
+ self.set_return_value(emulator, -1)
506
+ return
507
+
508
+ intake = FileIntake(file)
509
+
510
+ res = handle_scanf_format(self, intake, fmt, emulator)
511
+
512
+ self.set_return_value(emulator, res)
513
+
514
+
515
+ class Fseek(StdioModel):
516
+ name = "fseek"
517
+
518
+ # int fseek(FILE *file, long int offset, int origin);
519
+ argument_types = [ArgumentType.POINTER, ArgumentType.LONG, ArgumentType.INT]
520
+ return_type = ArgumentType.INT
521
+
522
+ def model(self, emulator: emulators.Emulator) -> None:
523
+ super().model(emulator)
524
+
525
+ filestar = self.get_arg1(emulator)
526
+ offset = self.get_arg2(emulator)
527
+ origin = self.get_arg3(emulator)
528
+
529
+ assert isinstance(filestar, int)
530
+ assert isinstance(offset, int)
531
+ assert isinstance(offset, int)
532
+
533
+ try:
534
+ fd = self._fdmgr.filestar_to_fd(filestar)
535
+ file = self._fdmgr.get(fd)
536
+ except FDIOError:
537
+ self.set_return_value(emulator, -1)
538
+ return
539
+
540
+ pos = file.seek(offset, origin)
541
+ self.set_return_value(emulator, pos)
542
+
543
+
544
+ class Ftell(StdioModel):
545
+ name = "ftell"
546
+
547
+ # long ftell(FILE *file);
548
+ argument_types = [ArgumentType.POINTER]
549
+ return_type = ArgumentType.LONG
550
+
551
+ def model(self, emulator: emulators.Emulator) -> None:
552
+ super().model(emulator)
553
+ filestar = self.get_arg1(emulator)
554
+
555
+ assert isinstance(filestar, int)
556
+
557
+ try:
558
+ fd = self._fdmgr.filestar_to_fd(filestar)
559
+ file = self._fdmgr.get(fd)
560
+ except FDIOError:
561
+ self.set_return_value(emulator, -1)
562
+
563
+ self.set_return_value(emulator, file.cursor)
564
+
565
+
566
+ class Fgetpos(StdioModel):
567
+ name = "fgetpos"
568
+
569
+ # int fgetpos(FILE *file, fpos_t *pos);
570
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
571
+ return_type = ArgumentType.INT
572
+
573
+ def model(self, emulator: emulators.Emulator) -> None:
574
+ super().model(emulator)
575
+
576
+ filestar = self.get_arg1(emulator)
577
+ ptr = self.get_arg2(emulator)
578
+
579
+ assert isinstance(filestar, int)
580
+ assert isinstance(ptr, int)
581
+
582
+ try:
583
+ fd = self._fdmgr.filestar_to_fd(filestar)
584
+ file = self._fdmgr.get(fd)
585
+ except FDIOError:
586
+ self.set_return_value(emulator, -1)
587
+
588
+ # Okay, this is a pain.
589
+ # fpos_t is platform-specific.
590
+ # On GNU Linux, it's always a struct, and always
591
+ # at least eight bytes.
592
+ # One fieldis the offset. No idea what the other is.
593
+ #
594
+ # If you read from inside this, I grump at you.
595
+
596
+ if self.platform.byteorder == Byteorder.LITTLE:
597
+ data = file.cursor.to_bytes(8, "little")
598
+ elif self.platform.byteorder == Byteorder.BIG:
599
+ data = file.cursor.to_bytes(8, "big")
600
+ else:
601
+ raise exceptions.ConfigurationError(
602
+ f"Can't encode int for byteorder {self.platform.byteorder}"
603
+ )
604
+
605
+ emulator.write_memory(ptr, data)
606
+ self.set_return_value(emulator, 0)
607
+
608
+
609
+ class Fsetpos(StdioModel):
610
+ name = "fsetpos"
611
+
612
+ # int ftell(FILE *file, fpos_t *pos);
613
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
614
+ return_type = ArgumentType.INT
615
+
616
+ def model(self, emulator: emulators.Emulator) -> None:
617
+ super().model(emulator)
618
+
619
+ filestar = self.get_arg1(emulator)
620
+ ptr = self.get_arg2(emulator)
621
+
622
+ assert isinstance(filestar, int)
623
+ assert isinstance(ptr, int)
624
+
625
+ try:
626
+ fd = self._fdmgr.filestar_to_fd(filestar)
627
+ file = self._fdmgr.get(fd)
628
+ except FDIOError:
629
+ self.set_return_value(emulator, -1)
630
+
631
+ # Okay, this is a pain.
632
+ # fpos_t is platform-specific.
633
+ # On GNU Linux, it's always a struct, and always
634
+ # at least eight bytes.
635
+ # One fieldis the offset. No idea what the other is.
636
+ #
637
+ # If you read from inside this, I grump at you.
638
+
639
+ data = emulator.read_memory(ptr, 8)
640
+
641
+ if self.platform.byteorder == Byteorder.LITTLE:
642
+ pos = int.from_bytes(data, "little")
643
+ elif self.platform.byteorder == Byteorder.BIG:
644
+ pos = int.from_bytes(data, "big")
645
+ else:
646
+ raise exceptions.ConfigurationError(
647
+ f"Can't encode int for byteorder {self.platform.byteorder}"
648
+ )
649
+
650
+ file.seek(pos, 0)
651
+ self.set_return_value(emulator, 0)
652
+
653
+
654
+ class Fwrite(StdioModel):
655
+ name = "fwrite"
656
+
657
+ # int fwrite(void *src, size_t size, size_t amt, FILE *file);
658
+ argument_types = [
659
+ ArgumentType.POINTER,
660
+ ArgumentType.SIZE_T,
661
+ ArgumentType.SIZE_T,
662
+ ArgumentType.POINTER,
663
+ ]
664
+ return_type = ArgumentType.SIZE_T
665
+
666
+ def model(self, emulator: emulators.Emulator) -> None:
667
+ super().model(emulator)
668
+
669
+ src = self.get_arg1(emulator)
670
+ size = self.get_arg2(emulator)
671
+ amt = self.get_arg3(emulator)
672
+ filestar = self.get_arg4(emulator)
673
+
674
+ assert isinstance(src, int)
675
+ assert isinstance(size, int)
676
+ assert isinstance(amt, int)
677
+ assert isinstance(filestar, int)
678
+
679
+ try:
680
+ fd = self._fdmgr.filestar_to_fd(filestar)
681
+ file = self._fdmgr.get(fd)
682
+
683
+ data = emulator.read_memory(src, size * amt)
684
+ file.write(data)
685
+ except FDIOError:
686
+ self.set_return_value(emulator, -1)
687
+ return
688
+
689
+ self.set_return_value(emulator, amt)
690
+
691
+
692
+ class Getc(Fgetc):
693
+ name = "getc"
694
+
695
+ # NOTE: getc and fgetc behave the same.
696
+ # getc may actually be a macro for fgetc
697
+
698
+
699
+ class Ungetc(StdioModel):
700
+ name = "ungetc"
701
+
702
+ # int ungetc(int c, FILE *file);
703
+ argument_types = [ArgumentType.INT, ArgumentType.POINTER]
704
+ return_type = ArgumentType.INT
705
+
706
+ def model(self, emulator: emulators.Emulator) -> None:
707
+ super().model(emulator)
708
+
709
+ char = self.get_arg1(emulator)
710
+ filestar = self.get_arg2(emulator)
711
+
712
+ assert isinstance(char, int)
713
+ assert isinstance(char, int)
714
+
715
+ try:
716
+ fd = self._fdmgr.filestar_to_fd(filestar)
717
+ file = self._fdmgr.get(fd)
718
+ file.ungetc(char)
719
+ except FDIOError:
720
+ self.set_return_value(emulator, -1)
721
+ return
722
+
723
+ self.set_return_value(emulator, char)
724
+
725
+
726
+ class Getchar(StdioModel):
727
+ name = "getchar"
728
+
729
+ # int getchar(void);
730
+ argument_types = []
731
+ return_type = ArgumentType.INT
732
+
733
+ def model(self, emulator: emulators.Emulator) -> None:
734
+ super().model(emulator)
735
+
736
+ # Use stdin
737
+ # TODO: If someone changes the struct pointed to by stdin, we're in trouble.
738
+ fd = 0
739
+
740
+ try:
741
+ file = self._fdmgr.get(fd)
742
+ except FDIOError:
743
+ self.set_return_value(emulator, -1)
744
+
745
+ data = file.read(1, ungetc=True)
746
+
747
+ self.set_return_value(emulator, data[0])
748
+
749
+
750
+ class Gets(StdioModel):
751
+ name = "gets"
752
+
753
+ # char *fgets(char *dst);
754
+ argument_types = [ArgumentType.POINTER, ArgumentType.SIZE_T, ArgumentType.POINTER]
755
+ return_type = ArgumentType.POINTER
756
+
757
+ def model(self, emulator: emulators.Emulator) -> None:
758
+ super().model(emulator)
759
+
760
+ dst = self.get_arg1(emulator)
761
+
762
+ assert isinstance(dst, int)
763
+
764
+ try:
765
+ fd = 0
766
+ file = self._fdmgr.get(fd)
767
+ except FDIOError:
768
+ self.set_return_value(emulator, 0)
769
+ return
770
+
771
+ data = file.read_string()
772
+ emulator.write_memory(dst, data)
773
+ self.set_return_value(emulator, dst)
774
+
775
+
776
+ class Printf(StdioModel):
777
+ name = "printf"
778
+
779
+ # int printf(const char *fmt, ...);
780
+ argument_types = [ArgumentType.POINTER]
781
+ return_type = ArgumentType.INT
782
+
783
+ def model(self, emulator: emulators.Emulator) -> None:
784
+ super().model(emulator)
785
+
786
+ fmt_addr = self.get_arg1(emulator)
787
+
788
+ assert isinstance(fmt_addr, int)
789
+
790
+ fmt_len = _emu_strlen(emulator, fmt_addr)
791
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
792
+ fmt = fmt_bytes.decode("utf-8")
793
+
794
+ output = parse_printf_format(self, fmt, emulator)
795
+ output_bytes = output.encode("utf-8")
796
+
797
+ fd = 1
798
+ try:
799
+ file = self._fdmgr.get(fd)
800
+ except FDIOError:
801
+ self.set_return_value(emulator, -1)
802
+ return
803
+
804
+ file.write(output_bytes)
805
+
806
+ self.set_return_value(emulator, len(output_bytes))
807
+
808
+
809
+ class Putc(Fputc):
810
+ name = "putc"
811
+
812
+ # NOTE: fputc and putc behave the same.
813
+ # putc may actually be a macro for fputc.
814
+
815
+
816
+ class Putchar(StdioModel):
817
+ name = "putchar"
818
+
819
+ # int putchar(int c);
820
+ argument_types = [ArgumentType.INT]
821
+ return_type = ArgumentType.INT
822
+
823
+ def model(self, emulator: emulators.Emulator) -> None:
824
+ super().model(emulator)
825
+
826
+ char = self.get_arg1(emulator)
827
+
828
+ assert isinstance(char, int)
829
+
830
+ # Use stdout
831
+ # TODO: If someone changes the FILE * in stdout, we're in trouble.
832
+ fd = 1
833
+
834
+ try:
835
+ file = self._fdmgr.get(fd)
836
+ except FDIOError:
837
+ self.set_return_value(emulator, -1)
838
+ return
839
+
840
+ file.write(bytes([char]))
841
+
842
+ self.set_return_value(emulator, char)
843
+
844
+
845
+ class Puts(StdioModel):
846
+ name = "puts"
847
+
848
+ # int puts(const char *s);
849
+ argument_types = [ArgumentType.POINTER]
850
+ return_type = ArgumentType.INT
851
+
852
+ def model(self, emulator: emulators.Emulator) -> None:
853
+ super().model(emulator)
854
+
855
+ ptr = self.get_arg1(emulator)
856
+
857
+ assert isinstance(ptr, int)
858
+
859
+ size = _emu_strlen(emulator, ptr)
860
+
861
+ data = emulator.read_memory(ptr, size)
862
+
863
+ # Use stdout
864
+ # TODO: If someone changes the FILE * in stdout, we're in trouble.
865
+ fd = 1
866
+
867
+ try:
868
+ file = self._fdmgr.get(fd)
869
+ except FDIOError:
870
+ self.set_return_value(emulator, -1)
871
+ return
872
+
873
+ file.write(data)
874
+ file.write(b"\n")
875
+
876
+ self.set_return_value(emulator, 0)
877
+
878
+
879
+ class Remove(StdioModel):
880
+ name = "remove"
881
+
882
+ # int remove(const char *path);
883
+ argument_types = [ArgumentType.POINTER]
884
+ return_type = ArgumentType.INT
885
+
886
+ # No file system; just returns true
887
+ imprecise = True
888
+
889
+ def __init__(self, address: int):
890
+ self._allow_imprecise = False
891
+ super().__init__(address)
892
+
893
+ @property
894
+ def allow_imprecise(self) -> bool:
895
+ return self._allow_imprecise or self._fdmgr.model_fs
896
+
897
+ @allow_imprecise.setter
898
+ def allow_imprecise(self, val: bool) -> None:
899
+ self._allow_imprecise = val
900
+
901
+ def model(self, emulator: emulators.Emulator) -> None:
902
+ super().model(emulator)
903
+
904
+ ptr = self.get_arg1(emulator)
905
+
906
+ assert isinstance(ptr, int)
907
+
908
+ size = _emu_strlen(emulator, ptr)
909
+
910
+ data = emulator.read_memory(ptr, size)
911
+
912
+ name = data.decode("utf-8")
913
+
914
+ if self._fdmgr.remove(name):
915
+ self.set_return_value(emulator, 0)
916
+ else:
917
+ self.set_return_value(emulator, -1)
918
+
919
+
920
+ class Rename(StdioModel):
921
+ name = "rename"
922
+
923
+ # int rename(const char *oldpath, const char *newpath);
924
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
925
+ return_type = ArgumentType.INT
926
+
927
+ # No file system; just returns true
928
+ imprecise = True
929
+
930
+ def __init__(self, address: int):
931
+ self._allow_imprecise = False
932
+ super().__init__(address)
933
+
934
+ @property
935
+ def allow_imprecise(self) -> bool:
936
+ return self._allow_imprecise or self._fdmgr.model_fs
937
+
938
+ @allow_imprecise.setter
939
+ def allow_imprecise(self, val: bool) -> None:
940
+ self._allow_imprecise = val
941
+
942
+ def model(self, emulator: emulators.Emulator) -> None:
943
+ super().model(emulator)
944
+
945
+ oldptr = self.get_arg1(emulator)
946
+ newptr = self.get_arg2(emulator)
947
+
948
+ assert isinstance(oldptr, int)
949
+ assert isinstance(newptr, int)
950
+
951
+ oldsize = _emu_strlen(emulator, oldptr)
952
+ newsize = _emu_strlen(emulator, newptr)
953
+
954
+ olddata = emulator.read_memory(oldptr, oldsize)
955
+ newdata = emulator.read_memory(newptr, newsize)
956
+
957
+ old = olddata.decode("utf-8")
958
+ new = newdata.decode("utf-8")
959
+
960
+ try:
961
+ self._fdmgr.rename(old, new)
962
+ self.set_return_value(emulator, 0)
963
+ except FDIOError:
964
+ self.set_return_value(emulator, -1)
965
+
966
+
967
+ class Rewind(StdioModel):
968
+ name = "rewind"
969
+
970
+ # void rewind(FILE *file);
971
+ argument_types = [ArgumentType.POINTER]
972
+ return_type = ArgumentType.VOID
973
+
974
+ def model(self, emulator: emulators.Emulator) -> None:
975
+ super().model(emulator)
976
+
977
+ filestar = self.get_arg1(emulator)
978
+
979
+ assert isinstance(filestar, int)
980
+
981
+ try:
982
+ fd = self._fdmgr.filestar_to_fd(filestar)
983
+ file = self._fdmgr.get(fd)
984
+ except FDIOError:
985
+ return
986
+
987
+ file.cursor = 0
988
+
989
+
990
+ class Scanf(StdioModel):
991
+ name = "scanf"
992
+
993
+ # int scanf(const char *fmt, ...);
994
+ argument_types = [ArgumentType.POINTER]
995
+ return_type = ArgumentType.INT
996
+
997
+ def model(self, emulator: emulators.Emulator) -> None:
998
+ super().model(emulator)
999
+
1000
+ fmt_addr = self.get_arg1(emulator)
1001
+
1002
+ assert isinstance(fmt_addr, int)
1003
+
1004
+ fmt_len = _emu_strlen(emulator, fmt_addr)
1005
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
1006
+ fmt = fmt_bytes.decode("utf-8")
1007
+
1008
+ try:
1009
+ fd = 0
1010
+ file = self._fdmgr.get(fd)
1011
+ except FDIOError:
1012
+ self.set_return_value(emulator, -1)
1013
+ return
1014
+
1015
+ intake = FileIntake(file)
1016
+
1017
+ res = handle_scanf_format(self, intake, fmt, emulator)
1018
+
1019
+ self.set_return_value(emulator, res)
1020
+
1021
+
1022
+ class Snprintf(StdioModel):
1023
+ name = "snprintf"
1024
+
1025
+ # int snprintf(char *dst, size_t size, const char *fmt, ...);
1026
+ argument_types = [ArgumentType.POINTER, ArgumentType.SIZE_T, ArgumentType.POINTER]
1027
+ return_type = ArgumentType.INT
1028
+
1029
+ def model(self, emulator: emulators.Emulator) -> None:
1030
+ super().model(emulator)
1031
+
1032
+ buf_addr = self.get_arg1(emulator)
1033
+ size = self.get_arg2(emulator)
1034
+ fmt_addr = self.get_arg3(emulator)
1035
+
1036
+ assert isinstance(buf_addr, int)
1037
+ assert isinstance(size, int)
1038
+ assert isinstance(fmt_addr, int)
1039
+
1040
+ fmt_len = _emu_strlen(emulator, fmt_addr)
1041
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
1042
+ fmt = fmt_bytes.decode("utf-8")
1043
+
1044
+ output = parse_printf_format(self, fmt, emulator)
1045
+ output_bytes = output.encode("utf-8")
1046
+ output_bytes += b"\0"
1047
+
1048
+ trunc_bytes = output_bytes
1049
+ if len(trunc_bytes) > size:
1050
+ trunc_bytes = trunc_bytes[: size - 1]
1051
+ trunc_bytes += b"\0"
1052
+
1053
+ if buf_addr != 0:
1054
+ emulator.write_memory(buf_addr, output_bytes)
1055
+
1056
+ self.set_return_value(emulator, len(output_bytes) - 1)
1057
+
1058
+
1059
+ class Sprintf(StdioModel):
1060
+ name = "sprintf"
1061
+
1062
+ # int sprintf(char *dst, const char *fmt, ...);
1063
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1064
+ return_type = ArgumentType.INT
1065
+
1066
+ def model(self, emulator: emulators.Emulator) -> None:
1067
+ super().model(emulator)
1068
+
1069
+ buf_addr = self.get_arg1(emulator)
1070
+ fmt_addr = self.get_arg2(emulator)
1071
+
1072
+ assert isinstance(buf_addr, int)
1073
+ assert isinstance(fmt_addr, int)
1074
+
1075
+ fmt_len = _emu_strlen(emulator, fmt_addr)
1076
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
1077
+ fmt = fmt_bytes.decode("utf-8")
1078
+
1079
+ output = parse_printf_format(self, fmt, emulator)
1080
+ output_bytes = output.encode("utf-8")
1081
+ output_bytes += b"\0"
1082
+
1083
+ if buf_addr != 0:
1084
+ emulator.write_memory(buf_addr, output_bytes)
1085
+
1086
+ self.set_return_value(emulator, len(output_bytes) - 1)
1087
+
1088
+
1089
+ class Sscanf(StdioModel):
1090
+ name = "sscanf"
1091
+
1092
+ # int sscanf(const char *src, const char *fmt, ...);
1093
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1094
+ return_type = ArgumentType.INT
1095
+
1096
+ def model(self, emulator: emulators.Emulator) -> None:
1097
+ super().model(emulator)
1098
+
1099
+ src_addr = self.get_arg1(emulator)
1100
+ fmt_addr = self.get_arg2(emulator)
1101
+
1102
+ assert isinstance(src_addr, int)
1103
+ assert isinstance(fmt_addr, int)
1104
+
1105
+ fmt_len = _emu_strlen(emulator, fmt_addr)
1106
+ fmt_bytes = emulator.read_memory(fmt_addr, fmt_len)
1107
+ fmt = fmt_bytes.decode("utf-8")
1108
+
1109
+ intake = StringIntake(src_addr, emulator)
1110
+
1111
+ res = handle_scanf_format(self, intake, fmt, emulator)
1112
+
1113
+ self.set_return_value(emulator, res)
1114
+
1115
+
1116
+ class Tmpfile(StdioModel):
1117
+ name = "tmpfile"
1118
+
1119
+ # FILE *tmpfile(void);
1120
+ argument_types = []
1121
+ return_type = ArgumentType.POINTER
1122
+
1123
+ def model(self, emulator: emulators.Emulator) -> None:
1124
+ super().model(emulator)
1125
+
1126
+ name = self._generate_tmpnam()
1127
+
1128
+ try:
1129
+ fd = self._fdmgr.open(
1130
+ name,
1131
+ readable=True,
1132
+ writable=True,
1133
+ create=True,
1134
+ truncate=False,
1135
+ append=False,
1136
+ seekable=True,
1137
+ )
1138
+ except FDIOError:
1139
+ self.set_return_value(emulator, 0)
1140
+ return
1141
+
1142
+ filestar = self._fdmgr.fd_to_filestar(fd)
1143
+ self.set_return_value(emulator, filestar)
1144
+
1145
+
1146
+ class Tmpnam(StdioModel):
1147
+ name = "tmpnam"
1148
+
1149
+ # char *tmpnam(char *name);
1150
+ argument_types = [ArgumentType.POINTER]
1151
+ return_type = ArgumentType.POINTER
1152
+
1153
+ def model(self, emulator: emulators.Emulator) -> None:
1154
+ super().model(emulator)
1155
+
1156
+ ptr = self.get_arg1(emulator)
1157
+
1158
+ assert isinstance(ptr, int)
1159
+
1160
+ if ptr == 0:
1161
+ raise NotImplementedError("Using tmpnam internal buffer not supported")
1162
+
1163
+ name = self._generate_tmpnam().encode("utf-8")
1164
+
1165
+ emulator.write_memory(ptr, name)
1166
+
1167
+ self.set_return_value(emulator, ptr)
1168
+
1169
+
1170
+ class Vfprintf(StdioModel):
1171
+ name = "vfprintf"
1172
+
1173
+ # int vfprintf(FILE *stream, const char *fmt, va_list args);
1174
+ # TODO: Figure out how to decode a va_list
1175
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1176
+ return_type = ArgumentType.INT
1177
+
1178
+ def model(self, emulator: emulators.Emulator) -> None:
1179
+ super().model(emulator)
1180
+ raise NotImplementedError()
1181
+
1182
+
1183
+ class Vfscanf(StdioModel):
1184
+ name = "vfscanf"
1185
+
1186
+ # int vfscanf(FILE *stream, const char *fmt, va_list args);
1187
+ # TODO: Figure out how to decode a va_list
1188
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1189
+ return_type = ArgumentType.INT
1190
+
1191
+ def model(self, emulator: emulators.Emulator) -> None:
1192
+ super().model(emulator)
1193
+ raise NotImplementedError()
1194
+
1195
+
1196
+ class Vprintf(StdioModel):
1197
+ name = "vprintf"
1198
+
1199
+ # int vprintf(const char *fmt, va_list args);
1200
+ # TODO: Figure out how to decode a va_list
1201
+ argument_types = [ArgumentType.POINTER]
1202
+ return_type = ArgumentType.INT
1203
+
1204
+ def model(self, emulator: emulators.Emulator) -> None:
1205
+ super().model(emulator)
1206
+ raise NotImplementedError()
1207
+
1208
+
1209
+ class Vscanf(StdioModel):
1210
+ name = "vscanf"
1211
+
1212
+ # int vscanf(const char *fmt, va_list args);
1213
+ # TODO: Figure out how to decode a va_list
1214
+ argument_types = [ArgumentType.POINTER]
1215
+ return_type = ArgumentType.INT
1216
+
1217
+ def model(self, emulator: emulators.Emulator) -> None:
1218
+ super().model(emulator)
1219
+ raise NotImplementedError()
1220
+
1221
+
1222
+ class Vsnprintf(StdioModel):
1223
+ name = "vsnprintf"
1224
+
1225
+ # int vsprintf(char *str, size_t len, const char *fmt, va_list args);
1226
+ # TODO: Figure out how to decode a va_list
1227
+ argument_types = [ArgumentType.POINTER, ArgumentType.SIZE_T, ArgumentType.POINTER]
1228
+ return_type = ArgumentType.INT
1229
+
1230
+ def model(self, emulator: emulators.Emulator) -> None:
1231
+ super().model(emulator)
1232
+ raise NotImplementedError()
1233
+
1234
+
1235
+ class Vsprintf(StdioModel):
1236
+ name = "vsprintf"
1237
+
1238
+ # int vsprintf(char *str, const char *fmt, va_list args);
1239
+ # TODO: Figure out how to decode a va_list
1240
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1241
+ return_type = ArgumentType.INT
1242
+
1243
+ def model(self, emulator: emulators.Emulator) -> None:
1244
+ super().model(emulator)
1245
+ raise NotImplementedError()
1246
+
1247
+
1248
+ class Vsscanf(StdioModel):
1249
+ name = "vsprintf"
1250
+
1251
+ # int vsscanf(char *str, const char *fmt, va_list args);
1252
+ # TODO: Figure out how to decode a va_list
1253
+ argument_types = [ArgumentType.POINTER, ArgumentType.POINTER]
1254
+ return_type = ArgumentType.INT
1255
+
1256
+ def model(self, emulator: emulators.Emulator) -> None:
1257
+ super().model(emulator)
1258
+ raise NotImplementedError()
1259
+
1260
+
1261
+ __all__ = [
1262
+ "Clearerr",
1263
+ "Fclose",
1264
+ "Feof",
1265
+ "Ferror",
1266
+ "Fflush",
1267
+ "Fgetc",
1268
+ "Fgetpos",
1269
+ "Fgets",
1270
+ "Fopen",
1271
+ "Fprintf",
1272
+ "Fputc",
1273
+ "Fputs",
1274
+ "Fread",
1275
+ "Freopen",
1276
+ "Fscanf",
1277
+ "Fseek",
1278
+ "Fsetpos",
1279
+ "Ftell",
1280
+ "Fwrite",
1281
+ "Getc",
1282
+ "Getchar",
1283
+ "Gets",
1284
+ "Printf",
1285
+ "Putc",
1286
+ "Putchar",
1287
+ "Puts",
1288
+ "Remove",
1289
+ "Rename",
1290
+ "Rewind",
1291
+ "Scanf",
1292
+ "Snprintf",
1293
+ "Sprintf",
1294
+ "Sscanf",
1295
+ "Tmpfile",
1296
+ "Tmpnam",
1297
+ "Ungetc",
1298
+ "Vfprintf",
1299
+ "Vfscanf",
1300
+ "Vprintf",
1301
+ "Vscanf",
1302
+ "Vsnprintf",
1303
+ "Vsprintf",
1304
+ "Vsscanf",
1305
+ ]