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.
- smallworld/analyses/__init__.py +8 -0
- smallworld/analyses/analysis.py +8 -67
- smallworld/analyses/code_coverage.py +1 -2
- smallworld/analyses/colorizer.py +301 -534
- smallworld/analyses/colorizer_def_use.py +217 -0
- smallworld/analyses/colorizer_summary.py +173 -83
- smallworld/analyses/field_detection/field_analysis.py +7 -8
- smallworld/analyses/field_detection/hints.py +1 -1
- smallworld/analyses/field_detection/malloc.py +2 -2
- smallworld/analyses/trace_execution.py +160 -0
- smallworld/analyses/trace_execution_types.py +42 -0
- smallworld/analyses/unstable/angr/divergence.py +1 -2
- smallworld/analyses/unstable/angr/model.py +5 -6
- smallworld/analyses/unstable/angr_nwbt.py +3 -4
- smallworld/analyses/unstable/code_coverage.py +2 -3
- smallworld/analyses/unstable/code_reachable.py +2 -3
- smallworld/analyses/unstable/control_flow_tracer.py +2 -3
- smallworld/analyses/unstable/pointer_finder.py +2 -3
- smallworld/analyses/unstable/utils/tui.py +71 -0
- smallworld/emulators/__init__.py +3 -1
- smallworld/emulators/angr/angr.py +30 -9
- smallworld/emulators/angr/machdefs/__init__.py +2 -0
- smallworld/emulators/angr/machdefs/aarch64.py +1 -1
- smallworld/emulators/angr/machdefs/amd64.py +0 -4
- smallworld/emulators/angr/machdefs/arm.py +0 -2
- smallworld/emulators/angr/machdefs/i386.py +0 -2
- smallworld/emulators/angr/machdefs/loongarch.py +340 -0
- smallworld/emulators/angr/machdefs/machdef.py +1 -8
- smallworld/emulators/angr/machdefs/mips.py +0 -2
- smallworld/emulators/angr/machdefs/mips64.py +0 -2
- smallworld/emulators/angr/machdefs/ppc.py +1 -2
- smallworld/emulators/angr/machdefs/riscv.py +8 -10
- smallworld/emulators/angr/machdefs/xtensa.py +7 -4
- smallworld/emulators/emulator.py +22 -0
- smallworld/emulators/ghidra/__init__.py +37 -0
- smallworld/emulators/ghidra/ghidra.py +513 -0
- smallworld/emulators/ghidra/machdefs/__init__.py +31 -0
- smallworld/emulators/ghidra/machdefs/aarch64.py +289 -0
- smallworld/emulators/ghidra/machdefs/amd64.py +185 -0
- smallworld/emulators/ghidra/machdefs/arm.py +370 -0
- smallworld/emulators/ghidra/machdefs/i386.py +109 -0
- smallworld/emulators/ghidra/machdefs/loongarch.py +162 -0
- smallworld/emulators/ghidra/machdefs/machdef.py +81 -0
- smallworld/emulators/ghidra/machdefs/mips.py +163 -0
- smallworld/emulators/ghidra/machdefs/mips64.py +186 -0
- smallworld/emulators/ghidra/machdefs/ppc.py +98 -0
- smallworld/emulators/ghidra/machdefs/riscv.py +208 -0
- smallworld/emulators/ghidra/machdefs/xtensa.py +21 -0
- smallworld/emulators/ghidra/typing.py +28 -0
- smallworld/emulators/hookable.py +18 -4
- smallworld/emulators/panda/machdefs/__init__.py +2 -2
- smallworld/emulators/panda/machdefs/aarch64.py +186 -11
- smallworld/emulators/panda/machdefs/amd64.py +103 -11
- smallworld/emulators/panda/machdefs/arm.py +216 -20
- smallworld/emulators/panda/machdefs/i386.py +30 -7
- smallworld/emulators/panda/machdefs/machdef.py +9 -16
- smallworld/emulators/panda/machdefs/mips.py +49 -5
- smallworld/emulators/panda/machdefs/mips64.py +57 -5
- smallworld/emulators/panda/machdefs/ppc.py +38 -13
- smallworld/emulators/panda/panda.py +146 -44
- smallworld/emulators/unicorn/__init__.py +2 -0
- smallworld/emulators/unicorn/machdefs/aarch64.py +253 -264
- smallworld/emulators/unicorn/machdefs/amd64.py +254 -259
- smallworld/emulators/unicorn/machdefs/arm.py +200 -212
- smallworld/emulators/unicorn/machdefs/i386.py +84 -90
- smallworld/emulators/unicorn/machdefs/machdef.py +2 -23
- smallworld/emulators/unicorn/machdefs/mips.py +127 -135
- smallworld/emulators/unicorn/unicorn.py +52 -13
- smallworld/helpers.py +4 -19
- smallworld/hinting/hinting.py +22 -192
- smallworld/hinting/hints.py +50 -18
- smallworld/instructions/bsid.py +8 -8
- smallworld/logging.py +4 -2
- smallworld/platforms/__init__.py +12 -0
- smallworld/platforms/defs/__init__.py +36 -0
- smallworld/platforms/defs/aarch64.py +450 -0
- smallworld/platforms/defs/amd64.py +463 -0
- smallworld/platforms/defs/arm.py +519 -0
- smallworld/platforms/defs/i386.py +258 -0
- smallworld/platforms/defs/loongarch.py +270 -0
- smallworld/platforms/defs/mips.py +321 -0
- smallworld/platforms/defs/mips64.py +313 -0
- smallworld/platforms/defs/platformdef.py +97 -0
- smallworld/platforms/defs/powerpc.py +259 -0
- smallworld/platforms/defs/riscv.py +257 -0
- smallworld/platforms/defs/xtensa.py +96 -0
- smallworld/{platforms.py → platforms/platforms.py} +3 -0
- smallworld/state/cpus/__init__.py +2 -0
- smallworld/state/cpus/aarch64.py +0 -9
- smallworld/state/cpus/amd64.py +6 -28
- smallworld/state/cpus/arm.py +0 -11
- smallworld/state/cpus/cpu.py +0 -11
- smallworld/state/cpus/i386.py +0 -7
- smallworld/state/cpus/loongarch.py +299 -0
- smallworld/state/cpus/mips.py +4 -47
- smallworld/state/cpus/mips64.py +18 -58
- smallworld/state/cpus/powerpc.py +2 -9
- smallworld/state/cpus/riscv.py +1 -11
- smallworld/state/cpus/xtensa.py +0 -5
- smallworld/state/memory/code.py +38 -2
- smallworld/state/memory/elf/__init__.py +5 -1
- smallworld/state/memory/elf/coredump/__init__.py +3 -0
- smallworld/state/memory/elf/coredump/coredump.py +46 -0
- smallworld/state/memory/elf/coredump/prstatus/__init__.py +27 -0
- smallworld/state/memory/elf/coredump/prstatus/aarch64.py +46 -0
- smallworld/state/memory/elf/coredump/prstatus/amd64.py +40 -0
- smallworld/state/memory/elf/coredump/prstatus/arm.py +53 -0
- smallworld/state/memory/elf/coredump/prstatus/i386.py +30 -0
- smallworld/state/memory/elf/coredump/prstatus/mips.py +55 -0
- smallworld/state/memory/elf/coredump/prstatus/mips64.py +57 -0
- smallworld/state/memory/elf/coredump/prstatus/ppc.py +82 -0
- smallworld/state/memory/elf/coredump/prstatus/prstatus.py +129 -0
- smallworld/state/memory/elf/elf.py +211 -57
- smallworld/state/memory/elf/register_state.py +36 -0
- smallworld/state/memory/elf/rela/__init__.py +2 -0
- smallworld/state/memory/elf/rela/aarch64.py +3 -1
- smallworld/state/memory/elf/rela/amd64.py +4 -2
- smallworld/state/memory/elf/rela/arm.py +4 -2
- smallworld/state/memory/elf/rela/i386.py +4 -2
- smallworld/state/memory/elf/rela/loongarch.py +32 -0
- smallworld/state/memory/elf/rela/mips.py +39 -18
- smallworld/state/memory/elf/rela/ppc.py +31 -14
- smallworld/state/memory/elf/structs.py +3 -0
- smallworld/state/memory/heap.py +2 -2
- smallworld/state/memory/memory.py +18 -0
- smallworld/state/memory/pe/__init__.py +3 -0
- smallworld/state/memory/pe/pe.py +361 -0
- smallworld/state/memory/pe/structs.py +60 -0
- smallworld/state/memory/stack/__init__.py +2 -0
- smallworld/state/memory/stack/loongarch.py +26 -0
- smallworld/state/models/__init__.py +29 -2
- smallworld/state/models/aarch64/__init__.py +1 -0
- smallworld/state/models/aarch64/systemv/__init__.py +6 -0
- smallworld/state/models/aarch64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/aarch64/systemv/c99/signal.py +16 -0
- smallworld/state/models/aarch64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/aarch64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/aarch64/systemv/c99/string.py +139 -0
- smallworld/state/models/aarch64/systemv/c99/time.py +61 -0
- smallworld/state/models/aarch64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/aarch64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/aarch64/systemv/posix/signal.py +157 -0
- smallworld/state/models/aarch64/systemv/systemv.py +80 -0
- smallworld/state/models/amd64/__init__.py +1 -0
- smallworld/state/models/amd64/systemv/__init__.py +6 -0
- smallworld/state/models/amd64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/amd64/systemv/c99/signal.py +16 -0
- smallworld/state/models/amd64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/amd64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/amd64/systemv/c99/string.py +139 -0
- smallworld/state/models/amd64/systemv/c99/time.py +61 -0
- smallworld/state/models/amd64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/amd64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/amd64/systemv/posix/signal.py +157 -0
- smallworld/state/models/amd64/systemv/systemv.py +78 -0
- smallworld/state/models/armel/__init__.py +1 -0
- smallworld/state/models/armel/systemv/__init__.py +6 -0
- smallworld/state/models/armel/systemv/c99/__init__.py +12 -0
- smallworld/state/models/armel/systemv/c99/signal.py +16 -0
- smallworld/state/models/armel/systemv/c99/stdio.py +265 -0
- smallworld/state/models/armel/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/armel/systemv/c99/string.py +139 -0
- smallworld/state/models/armel/systemv/c99/time.py +61 -0
- smallworld/state/models/armel/systemv/posix/__init__.py +6 -0
- smallworld/state/models/armel/systemv/posix/libgen.py +16 -0
- smallworld/state/models/armel/systemv/posix/signal.py +157 -0
- smallworld/state/models/armel/systemv/systemv.py +82 -0
- smallworld/state/models/armhf/__init__.py +1 -0
- smallworld/state/models/armhf/systemv/__init__.py +6 -0
- smallworld/state/models/armhf/systemv/c99/__init__.py +12 -0
- smallworld/state/models/armhf/systemv/c99/signal.py +16 -0
- smallworld/state/models/armhf/systemv/c99/stdio.py +265 -0
- smallworld/state/models/armhf/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/armhf/systemv/c99/string.py +139 -0
- smallworld/state/models/armhf/systemv/c99/time.py +61 -0
- smallworld/state/models/armhf/systemv/posix/__init__.py +6 -0
- smallworld/state/models/armhf/systemv/posix/libgen.py +16 -0
- smallworld/state/models/armhf/systemv/posix/signal.py +157 -0
- smallworld/state/models/armhf/systemv/systemv.py +77 -0
- smallworld/state/models/c99/__init__.py +12 -0
- smallworld/state/models/c99/fmt_print.py +915 -0
- smallworld/state/models/c99/fmt_scan.py +864 -0
- smallworld/state/models/c99/math.py +362 -0
- smallworld/state/models/c99/signal.py +71 -0
- smallworld/state/models/c99/stdio.py +1305 -0
- smallworld/state/models/c99/stdlib.py +595 -0
- smallworld/state/models/c99/string.py +674 -0
- smallworld/state/models/c99/time.py +340 -0
- smallworld/state/models/c99/utils.py +89 -0
- smallworld/state/models/cstd.py +759 -0
- smallworld/state/models/errno.py +581 -0
- smallworld/state/models/filedesc.py +515 -0
- smallworld/state/models/i386/__init__.py +1 -0
- smallworld/state/models/i386/systemv/__init__.py +6 -0
- smallworld/state/models/i386/systemv/c99/__init__.py +12 -0
- smallworld/state/models/i386/systemv/c99/signal.py +16 -0
- smallworld/state/models/i386/systemv/c99/stdio.py +265 -0
- smallworld/state/models/i386/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/i386/systemv/c99/string.py +139 -0
- smallworld/state/models/i386/systemv/c99/time.py +61 -0
- smallworld/state/models/i386/systemv/posix/__init__.py +6 -0
- smallworld/state/models/i386/systemv/posix/libgen.py +16 -0
- smallworld/state/models/i386/systemv/posix/signal.py +157 -0
- smallworld/state/models/i386/systemv/systemv.py +71 -0
- smallworld/state/models/loongarch64/__init__.py +1 -0
- smallworld/state/models/loongarch64/systemv/__init__.py +6 -0
- smallworld/state/models/loongarch64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/loongarch64/systemv/c99/signal.py +16 -0
- smallworld/state/models/loongarch64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/loongarch64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/loongarch64/systemv/c99/string.py +139 -0
- smallworld/state/models/loongarch64/systemv/c99/time.py +61 -0
- smallworld/state/models/loongarch64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/loongarch64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/loongarch64/systemv/posix/signal.py +157 -0
- smallworld/state/models/loongarch64/systemv/systemv.py +83 -0
- smallworld/state/models/mips/__init__.py +1 -0
- smallworld/state/models/mips/systemv/__init__.py +6 -0
- smallworld/state/models/mips/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips/systemv/c99/string.py +139 -0
- smallworld/state/models/mips/systemv/c99/time.py +61 -0
- smallworld/state/models/mips/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips/systemv/systemv.py +78 -0
- smallworld/state/models/mips64/__init__.py +1 -0
- smallworld/state/models/mips64/systemv/__init__.py +6 -0
- smallworld/state/models/mips64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips64/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips64/systemv/c99/string.py +139 -0
- smallworld/state/models/mips64/systemv/c99/time.py +61 -0
- smallworld/state/models/mips64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips64/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips64/systemv/systemv.py +98 -0
- smallworld/state/models/mips64el/__init__.py +1 -0
- smallworld/state/models/mips64el/systemv/__init__.py +6 -0
- smallworld/state/models/mips64el/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips64el/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips64el/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips64el/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips64el/systemv/c99/string.py +139 -0
- smallworld/state/models/mips64el/systemv/c99/time.py +61 -0
- smallworld/state/models/mips64el/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips64el/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips64el/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips64el/systemv/systemv.py +96 -0
- smallworld/state/models/mipsel/__init__.py +1 -0
- smallworld/state/models/mipsel/systemv/__init__.py +6 -0
- smallworld/state/models/mipsel/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mipsel/systemv/c99/signal.py +16 -0
- smallworld/state/models/mipsel/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mipsel/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mipsel/systemv/c99/string.py +139 -0
- smallworld/state/models/mipsel/systemv/c99/time.py +61 -0
- smallworld/state/models/mipsel/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mipsel/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mipsel/systemv/posix/signal.py +157 -0
- smallworld/state/models/mipsel/systemv/systemv.py +78 -0
- smallworld/state/models/model.py +27 -2
- smallworld/state/models/posix/__init__.py +6 -0
- smallworld/state/models/posix/libgen.py +123 -0
- smallworld/state/models/posix/signal.py +690 -0
- smallworld/state/models/powerpc/__init__.py +1 -0
- smallworld/state/models/powerpc/systemv/__init__.py +6 -0
- smallworld/state/models/powerpc/systemv/c99/__init__.py +12 -0
- smallworld/state/models/powerpc/systemv/c99/signal.py +16 -0
- smallworld/state/models/powerpc/systemv/c99/stdio.py +265 -0
- smallworld/state/models/powerpc/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/powerpc/systemv/c99/string.py +139 -0
- smallworld/state/models/powerpc/systemv/c99/time.py +61 -0
- smallworld/state/models/powerpc/systemv/posix/__init__.py +6 -0
- smallworld/state/models/powerpc/systemv/posix/libgen.py +16 -0
- smallworld/state/models/powerpc/systemv/posix/signal.py +157 -0
- smallworld/state/models/powerpc/systemv/systemv.py +93 -0
- smallworld/state/models/riscv64/__init__.py +1 -0
- smallworld/state/models/riscv64/systemv/__init__.py +6 -0
- smallworld/state/models/riscv64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/riscv64/systemv/c99/signal.py +16 -0
- smallworld/state/models/riscv64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/riscv64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/riscv64/systemv/c99/string.py +139 -0
- smallworld/state/models/riscv64/systemv/c99/time.py +61 -0
- smallworld/state/models/riscv64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/riscv64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/riscv64/systemv/posix/signal.py +157 -0
- smallworld/state/models/riscv64/systemv/systemv.py +85 -0
- smallworld/state/state.py +65 -24
- smallworld/state/unstable/elf.py +16 -31
- smallworld/utils.py +6 -1
- {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/METADATA +74 -42
- smallworld_re-2.0.0.dist-info/RECORD +374 -0
- {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/WHEEL +1 -1
- smallworld/state/models/x86/__init__.py +0 -2
- smallworld/state/models/x86/microsoftcdecl.py +0 -35
- smallworld/state/models/x86/systemv.py +0 -240
- smallworld_re-1.0.3.dist-info/RECORD +0 -166
- /smallworld/state/models/{posix.py → _posix.py} +0 -0
- {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/entry_points.txt +0 -0
- {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/licenses/LICENSE.txt +0 -0
- {smallworld_re-1.0.3.dist-info → smallworld_re-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,515 @@
|
|
1
|
+
import io
|
2
|
+
import sys
|
3
|
+
import typing
|
4
|
+
|
5
|
+
from ...exceptions import ConfigurationError
|
6
|
+
from ...platforms import ABI, Platform
|
7
|
+
|
8
|
+
|
9
|
+
class FDIOError(Exception):
|
10
|
+
"""Exception indicating an error case in the file IO model"""
|
11
|
+
|
12
|
+
pass
|
13
|
+
|
14
|
+
|
15
|
+
class FileDescriptor:
|
16
|
+
"""File Descriptor Representation"""
|
17
|
+
|
18
|
+
def __init__(
|
19
|
+
self,
|
20
|
+
name: str,
|
21
|
+
readable: bool = False,
|
22
|
+
writable: bool = False,
|
23
|
+
seekable: bool = False,
|
24
|
+
):
|
25
|
+
self.name = name
|
26
|
+
|
27
|
+
self.readable = readable
|
28
|
+
self.writable = writable
|
29
|
+
self.seekable = seekable
|
30
|
+
|
31
|
+
self.ungetc_buf = b""
|
32
|
+
|
33
|
+
self.cursor = 0
|
34
|
+
|
35
|
+
self.eof = False
|
36
|
+
|
37
|
+
@property
|
38
|
+
def _backing(self) -> typing.IO:
|
39
|
+
# Files aren't pickleable,
|
40
|
+
# and anyway we don't want contention on one file object.
|
41
|
+
# Instead, dynamically produce the backing file-like,
|
42
|
+
# with the understanding that it may need special handling.
|
43
|
+
raise FDIOError("File {self.name} has no backing")
|
44
|
+
|
45
|
+
def read(self, size: int, ungetc: bool = False) -> bytes:
|
46
|
+
"""Read data from this file descriptor
|
47
|
+
|
48
|
+
Arguments:
|
49
|
+
size: Number of bytes to read
|
50
|
+
ungetc: Set to true to use the 'ungetc' buffer
|
51
|
+
"""
|
52
|
+
if not self.readable:
|
53
|
+
raise FDIOError(f"File {self.name} is not readable")
|
54
|
+
|
55
|
+
# NOTE: This integrates support for ungetc.
|
56
|
+
# This feature is technically part of FILE * objects;
|
57
|
+
# ungetc effectively appends bytes to the beg
|
58
|
+
ungetc_data = b""
|
59
|
+
if ungetc and len(self.ungetc_buf) > 0:
|
60
|
+
if size == -1:
|
61
|
+
ungetc_data = self.ungetc_buf
|
62
|
+
self.ungetc_buf = b""
|
63
|
+
else:
|
64
|
+
ungetc_data = self.ungetc_buf[0:size]
|
65
|
+
self.ungetc_buf = self.ungetc_buf[size:]
|
66
|
+
|
67
|
+
size -= len(ungetc_data)
|
68
|
+
|
69
|
+
file = self._backing
|
70
|
+
|
71
|
+
if self.seekable:
|
72
|
+
# File is seekable; mimic it against the back end.
|
73
|
+
file.seek(self.cursor, 0)
|
74
|
+
|
75
|
+
data: typing.Union[str, bytes] = b""
|
76
|
+
if size != 0:
|
77
|
+
data = file.read(size)
|
78
|
+
self.cursor += len(data)
|
79
|
+
if len(data) != size:
|
80
|
+
print("EOF")
|
81
|
+
self.eof = True
|
82
|
+
|
83
|
+
if isinstance(data, str):
|
84
|
+
# This is a text file. Need to encode the result
|
85
|
+
assert hasattr(file, "encoding")
|
86
|
+
return ungetc_data + data.encode(file.encoding)
|
87
|
+
else:
|
88
|
+
return ungetc_data + data
|
89
|
+
|
90
|
+
def read_string(self, size: int = -1) -> bytes:
|
91
|
+
"""Read a newline-terminated string from this file
|
92
|
+
|
93
|
+
Arguments
|
94
|
+
size: Maximum number of bytes to read. Defaults to as many as possible
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
String read from file
|
98
|
+
"""
|
99
|
+
out = b""
|
100
|
+
size -= 1
|
101
|
+
while size != 0:
|
102
|
+
c = self.read(1)
|
103
|
+
if len(c) < 1:
|
104
|
+
break
|
105
|
+
out += c
|
106
|
+
|
107
|
+
if c == b"\n":
|
108
|
+
break
|
109
|
+
|
110
|
+
if size > 0:
|
111
|
+
size -= 1
|
112
|
+
out += b"\0"
|
113
|
+
return out
|
114
|
+
|
115
|
+
def write(self, data: bytes) -> None:
|
116
|
+
"""Write data to this file
|
117
|
+
|
118
|
+
Arguments:
|
119
|
+
data: Bytes to write to this file
|
120
|
+
"""
|
121
|
+
if not self.writable:
|
122
|
+
raise FDIOError(f"File {self.name} is not writable")
|
123
|
+
|
124
|
+
# TODO: Model the effects of ungetc.
|
125
|
+
# By observation, mixing writes with ungetc is unsupported;
|
126
|
+
# the test program segfaulted when I wran fputc after ungetc
|
127
|
+
|
128
|
+
file = self._backing
|
129
|
+
|
130
|
+
if self.seekable:
|
131
|
+
file.seek(self.cursor, 0)
|
132
|
+
|
133
|
+
if hasattr(file, "encoding"):
|
134
|
+
# File is a text file. Need to encode the results
|
135
|
+
file.write(data.decode(file.encoding))
|
136
|
+
else:
|
137
|
+
file.write(data)
|
138
|
+
|
139
|
+
self.cursor += len(data)
|
140
|
+
|
141
|
+
def seek(self, pos: int, whence: int) -> int:
|
142
|
+
"""Set the cursor for this file
|
143
|
+
|
144
|
+
Arguments:
|
145
|
+
pos: Position, possibly relative
|
146
|
+
whence: How to interpret 'pos'. See real implementations for possible values
|
147
|
+
"""
|
148
|
+
if not self.seekable:
|
149
|
+
raise FDIOError(f"File {self.name} is not seekable")
|
150
|
+
|
151
|
+
if whence == 0:
|
152
|
+
self.cursor = pos
|
153
|
+
elif whence == 1:
|
154
|
+
self.cursor += pos
|
155
|
+
elif whence == 2:
|
156
|
+
# Figure out how to find the end of the stream
|
157
|
+
raise NotImplementedError()
|
158
|
+
else:
|
159
|
+
raise FDIOError(f"Unknown 'whence' {whence} when seeking {self.name}")
|
160
|
+
|
161
|
+
return self.cursor
|
162
|
+
|
163
|
+
def ungetc(self, char: int) -> None:
|
164
|
+
"""Push a character back to the buffer
|
165
|
+
|
166
|
+
In real life, this is only supported by stdio FILE* objects.
|
167
|
+
It pushes the character to an internal buffer that's
|
168
|
+
read from before the actual stream gets read.
|
169
|
+
|
170
|
+
Its interactions with 'write', 'seek', and readingf from 'cursor'
|
171
|
+
are all undefined.
|
172
|
+
|
173
|
+
Arguments:
|
174
|
+
char: Character to push
|
175
|
+
"""
|
176
|
+
if not self.readable:
|
177
|
+
raise FDIOError(f"File {self.name} is not readable")
|
178
|
+
|
179
|
+
self.ungetc_buf = bytes([char]) + self.ungetc_buf
|
180
|
+
|
181
|
+
|
182
|
+
class BytesFileDescriptor(FileDescriptor):
|
183
|
+
"""File descriptor backed by a byte string."""
|
184
|
+
|
185
|
+
def __init__(
|
186
|
+
self,
|
187
|
+
name: str,
|
188
|
+
initial: typing.Union[bytes, io.BytesIO] = b"",
|
189
|
+
readable: bool = False,
|
190
|
+
writable: bool = False,
|
191
|
+
seekable: bool = False,
|
192
|
+
):
|
193
|
+
super().__init__(name, readable=readable, writable=writable, seekable=seekable)
|
194
|
+
if isinstance(initial, bytes):
|
195
|
+
initial = io.BytesIO(initial)
|
196
|
+
self.backing_io = initial
|
197
|
+
|
198
|
+
@property
|
199
|
+
def _backing(self) -> typing.IO:
|
200
|
+
return self.backing_io
|
201
|
+
|
202
|
+
|
203
|
+
class StdinFileDescriptor(FileDescriptor):
|
204
|
+
"""File descriptor backed by host's stdin.
|
205
|
+
|
206
|
+
Read-only, not seekable.
|
207
|
+
"""
|
208
|
+
|
209
|
+
def __init__(self):
|
210
|
+
super().__init__("stdin", readable=True)
|
211
|
+
|
212
|
+
@property
|
213
|
+
def _backing(self) -> typing.IO:
|
214
|
+
return sys.stdin
|
215
|
+
|
216
|
+
|
217
|
+
class StdoutFileDescriptor(FileDescriptor):
|
218
|
+
"""File descriptor backed by host's stdout.
|
219
|
+
|
220
|
+
Write-only, not seekable.
|
221
|
+
"""
|
222
|
+
|
223
|
+
def __init__(self):
|
224
|
+
super().__init__("stdout", writable=True)
|
225
|
+
|
226
|
+
@property
|
227
|
+
def _backing(self) -> typing.IO:
|
228
|
+
return sys.stdout
|
229
|
+
|
230
|
+
|
231
|
+
class StderrFileDescriptor(FileDescriptor):
|
232
|
+
"""File descriptor backed by host's stderr.
|
233
|
+
|
234
|
+
Write-only, not seekable.
|
235
|
+
"""
|
236
|
+
|
237
|
+
def __init__(self):
|
238
|
+
super().__init__("stderr", writable=True)
|
239
|
+
|
240
|
+
@property
|
241
|
+
def _backing(self) -> typing.IO:
|
242
|
+
return sys.stderr
|
243
|
+
|
244
|
+
|
245
|
+
class FileDescriptorManager:
|
246
|
+
"""Manager for wrangling file descriptors
|
247
|
+
|
248
|
+
This handles open, close, and other file descriptor
|
249
|
+
manipulation operations. It also lets you access the file descriptor
|
250
|
+
representations themselves.
|
251
|
+
|
252
|
+
This is a unified model that supports C99,
|
253
|
+
and is pretty much identical between System V and Windows.
|
254
|
+
|
255
|
+
It also supports an extermely basic filesystem model.
|
256
|
+
It's disabled by default, and enabled by setting 'model_fs' to True.
|
257
|
+
Its utility is currently extremely limited;
|
258
|
+
it has no directory tree or permissions model,
|
259
|
+
but it can help for very basic interactions.
|
260
|
+
|
261
|
+
There can absolutely be ABI-specific subclasses.
|
262
|
+
"""
|
263
|
+
|
264
|
+
_singletons: typing.Dict[
|
265
|
+
typing.Tuple[Platform, ABI], "FileDescriptorManager"
|
266
|
+
] = dict()
|
267
|
+
|
268
|
+
def __init__(self):
|
269
|
+
# Enables full FS modeling.
|
270
|
+
# By default, this will
|
271
|
+
self.model_fs = False
|
272
|
+
|
273
|
+
self._fds = dict()
|
274
|
+
self._files = dict()
|
275
|
+
|
276
|
+
# Allocate stdstreams
|
277
|
+
# NOTE: This is POSIX-specific
|
278
|
+
self._fds[0] = StdinFileDescriptor()
|
279
|
+
self._fds[1] = StdoutFileDescriptor()
|
280
|
+
self._fds[2] = StderrFileDescriptor()
|
281
|
+
|
282
|
+
def add_file(self, name: str, init: bytes = b"") -> None:
|
283
|
+
"""Add a file to the manager
|
284
|
+
|
285
|
+
This allows basic support for opening files
|
286
|
+
without creating them.
|
287
|
+
|
288
|
+
As of now, there is no actual file tree support;
|
289
|
+
whatever string is used as the name is what will match.
|
290
|
+
|
291
|
+
Arguments:
|
292
|
+
name: Name or path of the file to place
|
293
|
+
init: Initial bytes contained in that file
|
294
|
+
"""
|
295
|
+
if not self.model_fs:
|
296
|
+
raise ConfigurationError("Full FS support not enabled.")
|
297
|
+
|
298
|
+
self._files[name] = io.BytesIO(init)
|
299
|
+
|
300
|
+
def get_file(self, name: str) -> io.BytesIO:
|
301
|
+
"""Get the backing stream behind a file
|
302
|
+
|
303
|
+
Arguments:
|
304
|
+
name: The name to look up
|
305
|
+
|
306
|
+
Returns:
|
307
|
+
The file-like object storing the byte stream.
|
308
|
+
"""
|
309
|
+
if name in self._files:
|
310
|
+
return self._files[name]
|
311
|
+
|
312
|
+
raise KeyError(f"No file named {name}")
|
313
|
+
|
314
|
+
def open(
|
315
|
+
self,
|
316
|
+
name: str,
|
317
|
+
readable: bool,
|
318
|
+
writable: bool,
|
319
|
+
create: bool,
|
320
|
+
truncate: bool,
|
321
|
+
append: bool,
|
322
|
+
seekable: bool = True,
|
323
|
+
) -> int:
|
324
|
+
"""Mimic opening a file
|
325
|
+
|
326
|
+
This will behave a bit differently depending
|
327
|
+
on whether 'self.model_fs' is set.
|
328
|
+
|
329
|
+
If it's unset, it will create file descriptors blindly,
|
330
|
+
and attempting to interact with them will raise exceptions.
|
331
|
+
|
332
|
+
If it's set, it will use the basic file model; see add_file() and get_file().
|
333
|
+
|
334
|
+
As of now, there is no actual file tree support;
|
335
|
+
the name is merely used as a label.
|
336
|
+
|
337
|
+
Arguments:
|
338
|
+
name: Name of the file to open
|
339
|
+
readable: Whether the file should be readable
|
340
|
+
writable: Whether the file should be writable
|
341
|
+
create: Whether the file should be created if it doesn't exist.
|
342
|
+
truncate: Whether the file should be truncated when opened
|
343
|
+
append: Whether the cursor should be set at the end of the file
|
344
|
+
seekable: Whether the file should be seekable
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
An integer file descriptor
|
348
|
+
"""
|
349
|
+
|
350
|
+
# Limited to 256 file descriptors thanks to shenanigans with FILE * management.
|
351
|
+
# If you need more than 256 file descriptors in a micro-execution context,
|
352
|
+
# I have many questions.
|
353
|
+
for fd in range(0, 1 << 8):
|
354
|
+
if fd not in self._fds:
|
355
|
+
if self.model_fs:
|
356
|
+
if name not in self._files:
|
357
|
+
if not create:
|
358
|
+
raise FDIOError(
|
359
|
+
f"{name} does not exist, and creation not specified"
|
360
|
+
)
|
361
|
+
self.add_file(name, b"")
|
362
|
+
|
363
|
+
initial = self._files[name]
|
364
|
+
|
365
|
+
if truncate:
|
366
|
+
initial.truncate()
|
367
|
+
|
368
|
+
self._fds[fd] = BytesFileDescriptor(
|
369
|
+
name,
|
370
|
+
initial,
|
371
|
+
readable=readable,
|
372
|
+
writable=writable,
|
373
|
+
seekable=seekable,
|
374
|
+
)
|
375
|
+
|
376
|
+
if append:
|
377
|
+
self._fds[fd].cursor = len(initial.getvalue())
|
378
|
+
else:
|
379
|
+
self._fds[fd] = FileDescriptor(
|
380
|
+
name, readable=readable, writable=writable, seekable=seekable
|
381
|
+
)
|
382
|
+
return fd
|
383
|
+
raise FDIOError("Ran out of fds")
|
384
|
+
|
385
|
+
def close(self, fd: int) -> None:
|
386
|
+
"""Close a file
|
387
|
+
|
388
|
+
Arguments:
|
389
|
+
fd: Integer file descriptor
|
390
|
+
"""
|
391
|
+
if fd not in self._fds:
|
392
|
+
raise FDIOError(f"Unknown fd {fd}")
|
393
|
+
|
394
|
+
del self._fds[fd]
|
395
|
+
|
396
|
+
def get(self, fd: int) -> FileDescriptor:
|
397
|
+
"""Get the file representaiton by its integer file descriptor
|
398
|
+
|
399
|
+
Arguments:
|
400
|
+
fd: The integer file descriptor
|
401
|
+
|
402
|
+
Returns:
|
403
|
+
The file representation tied to 'fd'.
|
404
|
+
"""
|
405
|
+
if fd not in self._fds:
|
406
|
+
raise FDIOError(f"Unknown fd {fd}")
|
407
|
+
|
408
|
+
return self._fds[fd]
|
409
|
+
|
410
|
+
def rename(self, old: str, new: str) -> None:
|
411
|
+
"""Rename a file.
|
412
|
+
|
413
|
+
Only available if model_fs is set.
|
414
|
+
|
415
|
+
As of now, there is no actual file tree support;
|
416
|
+
the name is merely used as a label.
|
417
|
+
|
418
|
+
Arguments:
|
419
|
+
old: The current name of the file
|
420
|
+
new: The new name of the file
|
421
|
+
"""
|
422
|
+
if not self.model_fs:
|
423
|
+
return
|
424
|
+
|
425
|
+
if old not in self._files:
|
426
|
+
raise FDIOError(f"Unknown file {old}")
|
427
|
+
self._files[new] = self._files[old]
|
428
|
+
del self._files[old]
|
429
|
+
|
430
|
+
def remove(self, name: str) -> bool:
|
431
|
+
"""Remove a file
|
432
|
+
|
433
|
+
Is a no-op if model_fs is not set.
|
434
|
+
|
435
|
+
As of now, there is no actual file tree support;
|
436
|
+
the name is merely used as a label.
|
437
|
+
|
438
|
+
Arguments:
|
439
|
+
name: Name of the file to remove
|
440
|
+
Returns:
|
441
|
+
True if model_fs is not set, or if the file was removed
|
442
|
+
"""
|
443
|
+
|
444
|
+
if self.model_fs:
|
445
|
+
if name in self._files:
|
446
|
+
del self._files[name]
|
447
|
+
return True
|
448
|
+
return False
|
449
|
+
else:
|
450
|
+
return True
|
451
|
+
|
452
|
+
# Magic number for identifying FILE * pointers created by this API.
|
453
|
+
# ASCII for 'FI*'
|
454
|
+
#
|
455
|
+
# FILE * created by these models don't point to real structs.
|
456
|
+
# Rather, they're an encoded form of the file descriptor;
|
457
|
+
# the fd number is the LSB, with magic in bytes 1 through 3.
|
458
|
+
#
|
459
|
+
# On a 64-bit ABI, the upper four bytes should be zero;
|
460
|
+
# I don't want to write two models for this.
|
461
|
+
#
|
462
|
+
# Functions that allow for multiple FILE * structs per FD
|
463
|
+
# can go jump in a puddle.
|
464
|
+
filestar_magic = 0x47492A
|
465
|
+
|
466
|
+
@classmethod
|
467
|
+
def filestar_to_fd(cls, ptr: int) -> int:
|
468
|
+
"""Convert a FILE* pointer to an integer file descriptor
|
469
|
+
|
470
|
+
This will attempt to detect if the FILE* was actually created
|
471
|
+
by SmallWorld's model. If not, it raises an exception.
|
472
|
+
|
473
|
+
Arguments:
|
474
|
+
ptr: The FILE* pointer to decode
|
475
|
+
|
476
|
+
Returns:
|
477
|
+
The associated integer file descriptor
|
478
|
+
"""
|
479
|
+
if (ptr >> 8) != cls.filestar_magic:
|
480
|
+
raise FDIOError(f"FILE * {hex(ptr)} is not a FILE * created by this model.")
|
481
|
+
|
482
|
+
return ptr & 0xFF
|
483
|
+
|
484
|
+
@classmethod
|
485
|
+
def fd_to_filestar(cls, fd: int) -> int:
|
486
|
+
"""Convert an integer file descriptor to a FILE* pointer
|
487
|
+
|
488
|
+
Arguments:
|
489
|
+
fd: The integer file descriptor to encode
|
490
|
+
|
491
|
+
Returns:
|
492
|
+
The associated FILE* pointer
|
493
|
+
"""
|
494
|
+
return cls.filestar_magic << 8 | fd
|
495
|
+
|
496
|
+
@classmethod
|
497
|
+
def for_platform(cls, platform: Platform, abi: ABI):
|
498
|
+
"""Get an instance of this class for the desired platform
|
499
|
+
|
500
|
+
NOTE: This isn't a true singleton, and I want it that way.
|
501
|
+
Everything that asks for a manager during setup
|
502
|
+
should get the same instance,
|
503
|
+
but deep-copies of Machines should get their own managers
|
504
|
+
|
505
|
+
Arguments:
|
506
|
+
platform: The desired platform
|
507
|
+
abi: The desired ABI
|
508
|
+
|
509
|
+
Returns:
|
510
|
+
An instance of the manager for the platform
|
511
|
+
"""
|
512
|
+
if (platform, abi) not in cls._singletons:
|
513
|
+
# TODO: Actually implement this when I have multiple implementations
|
514
|
+
cls._singletons[(platform, abi)] = cls()
|
515
|
+
return cls._singletons[(platform, abi)]
|
@@ -0,0 +1 @@
|
|
1
|
+
from .systemv import __all__ as __sysv__ # noqa: F401
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from .signal import * # noqa F401,F403
|
2
|
+
from .signal import __all__ as __signal__
|
3
|
+
from .stdio import * # noqa F401,F403
|
4
|
+
from .stdio import __all__ as __stdio__
|
5
|
+
from .stdlib import * # noqa F401,F403
|
6
|
+
from .stdlib import __all__ as __stdlib__
|
7
|
+
from .string import * # noqa F401,F403
|
8
|
+
from .string import __all__ as __string__
|
9
|
+
from .time import * # noqa F401,F403
|
10
|
+
from .time import __all__ as __time__
|
11
|
+
|
12
|
+
__all__ = __signal__ + __stdlib__ + __string__ + __stdio__ + __time__
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from ....c99.signal import Raise, Signal
|
2
|
+
from ..systemv import I386SysVModel
|
3
|
+
|
4
|
+
|
5
|
+
class I386SysVRaise(Raise, I386SysVModel):
|
6
|
+
pass
|
7
|
+
|
8
|
+
|
9
|
+
class I386SysVSignal(Signal, I386SysVModel):
|
10
|
+
pass
|
11
|
+
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"I386SysVRaise",
|
15
|
+
"I386SysVSignal",
|
16
|
+
]
|