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,864 @@
|
|
1
|
+
import abc
|
2
|
+
import re
|
3
|
+
import struct
|
4
|
+
|
5
|
+
from ....emulators import Emulator
|
6
|
+
from ....platforms import Byteorder
|
7
|
+
from ..cstd import ArgumentType, CStdModel, VariadicContext
|
8
|
+
from ..filedesc import FileDescriptor
|
9
|
+
|
10
|
+
|
11
|
+
class FormatConversionError(Exception):
|
12
|
+
pass
|
13
|
+
|
14
|
+
|
15
|
+
class InputEndedError(Exception):
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
class Intake(metaclass=abc.ABCMeta):
|
20
|
+
"""Abstract class for input stream
|
21
|
+
|
22
|
+
The format scan algorithms need to scan both files
|
23
|
+
and strings. I don't want to write two models.
|
24
|
+
"""
|
25
|
+
|
26
|
+
def __init__(self):
|
27
|
+
self.cursor = 0
|
28
|
+
|
29
|
+
@abc.abstractmethod
|
30
|
+
def peek(self) -> str:
|
31
|
+
raise NotImplementedError()
|
32
|
+
|
33
|
+
@abc.abstractmethod
|
34
|
+
def push(self, data: str) -> None:
|
35
|
+
raise NotImplementedError()
|
36
|
+
|
37
|
+
@abc.abstractmethod
|
38
|
+
def pop(self) -> None:
|
39
|
+
raise NotImplementedError()
|
40
|
+
|
41
|
+
|
42
|
+
class FileIntake(Intake):
|
43
|
+
"""Input stream backed by a file
|
44
|
+
|
45
|
+
That is, a file modeled by the stdio models.
|
46
|
+
"""
|
47
|
+
|
48
|
+
def __init__(self, file: FileDescriptor):
|
49
|
+
super().__init__()
|
50
|
+
self.file = file
|
51
|
+
|
52
|
+
def peek(self) -> str:
|
53
|
+
data = self.file.read(1, ungetc=True)
|
54
|
+
if len(data) == 0:
|
55
|
+
raise InputEndedError()
|
56
|
+
|
57
|
+
self.file.ungetc(data[0])
|
58
|
+
|
59
|
+
if data == b"\0":
|
60
|
+
raise InputEndedError()
|
61
|
+
|
62
|
+
return data.decode("utf-8")
|
63
|
+
|
64
|
+
def push(self, data: str) -> None:
|
65
|
+
raw = data.encode("utf-8")
|
66
|
+
for char in reversed(raw):
|
67
|
+
self.file.ungetc(char)
|
68
|
+
|
69
|
+
self.cursor -= len(data)
|
70
|
+
|
71
|
+
def pop(self) -> None:
|
72
|
+
self.file.read(1, ungetc=True)
|
73
|
+
self.cursor += 1
|
74
|
+
|
75
|
+
|
76
|
+
class StringIntake(Intake):
|
77
|
+
"""Input stream backed by memory.
|
78
|
+
|
79
|
+
Data is read on-demand from the emulator
|
80
|
+
"""
|
81
|
+
|
82
|
+
def __init__(self, address: int, emulator: Emulator):
|
83
|
+
super().__init__()
|
84
|
+
self.address = address
|
85
|
+
self.emulator = emulator
|
86
|
+
|
87
|
+
def peek(self) -> str:
|
88
|
+
data = self.emulator.read_memory(self.address + self.cursor, 1)
|
89
|
+
if data == b"\0":
|
90
|
+
raise InputEndedError()
|
91
|
+
return data.decode("utf-8")
|
92
|
+
|
93
|
+
def push(self, data: str) -> None:
|
94
|
+
self.cursor -= len(data)
|
95
|
+
|
96
|
+
def pop(self) -> None:
|
97
|
+
self.cursor += 1
|
98
|
+
|
99
|
+
|
100
|
+
# Conversion specifiers:
|
101
|
+
#
|
102
|
+
# Group 1: Zero or one '*' flags
|
103
|
+
#
|
104
|
+
# Group 2: Zero or one maximum width specifiers
|
105
|
+
#
|
106
|
+
# Group 3: Zero or one length specifiers
|
107
|
+
#
|
108
|
+
# Group 4: Conversion ID
|
109
|
+
|
110
|
+
# Signed decimal int conversion
|
111
|
+
#
|
112
|
+
# Allowed Width Specifiers
|
113
|
+
# - 'hh': char
|
114
|
+
# - 'h': short
|
115
|
+
# - '': int
|
116
|
+
# - 'l': long
|
117
|
+
# - 'll', 'L', 'q': long long
|
118
|
+
# - 'z': ssize_t
|
119
|
+
# - 'j': intmax_t
|
120
|
+
# - t: ptrdiff_t
|
121
|
+
#
|
122
|
+
# Allowed Conversions:
|
123
|
+
# - 'd', 'i': signed decimal integer
|
124
|
+
sint_re = re.compile(r"%([*]?)([0-9]*)(hh|h|l|ll|L|q|z|j|t|)(d|i)")
|
125
|
+
|
126
|
+
# Unsigned int conversion
|
127
|
+
#
|
128
|
+
# Allowed Width Specifiers
|
129
|
+
# - 'hh': unsigned char
|
130
|
+
# - 'h': unsigned short
|
131
|
+
# - '': unsigned int
|
132
|
+
# - 'l': unsigned long
|
133
|
+
# - 'll', 'L', 'q': unsigned long long
|
134
|
+
# - 'z': size_t
|
135
|
+
# - 'j': intmax_t
|
136
|
+
# - t: ptrdiff_t
|
137
|
+
#
|
138
|
+
# Allowed Conversions:
|
139
|
+
# - 'o': unsigned octal integer
|
140
|
+
# - 'u': unsigned decimal integer
|
141
|
+
# - 'x', 'X': unsigned hexadecimal integer
|
142
|
+
uint_re = re.compile(r"%([*]?)([0-9]*)(hh|h|l|ll|L|q|z|j|t|)(o|u|x|X)")
|
143
|
+
|
144
|
+
# Floating-point conversion
|
145
|
+
#
|
146
|
+
# Allowed Width Specifiers
|
147
|
+
# - '': float
|
148
|
+
# - 'l': double
|
149
|
+
# - 'll', 'L', 'q': long double
|
150
|
+
#
|
151
|
+
# Allowed Conversions:
|
152
|
+
# - 'e', 'E', 'f', 'g', 'G', 'a', 'A': signed floating-point
|
153
|
+
float_re = re.compile(r"%([*]?)([0-9]*)(l|ll|L|q|)(e|E|f|g|a)")
|
154
|
+
|
155
|
+
# Character conversion
|
156
|
+
#
|
157
|
+
# Allowed Width Specifiers
|
158
|
+
# - '': char
|
159
|
+
# - 'l': wchar_t
|
160
|
+
#
|
161
|
+
# Allowed Conversions
|
162
|
+
# - 'c': Character
|
163
|
+
char_re = re.compile(r"%([*]?)([0-9]*)(l|)(c)")
|
164
|
+
|
165
|
+
# String conversion
|
166
|
+
#
|
167
|
+
# Allowed Width Specifiers:
|
168
|
+
# - '': char
|
169
|
+
# - 'l': wchar_t
|
170
|
+
#
|
171
|
+
# Allowed Conversions:
|
172
|
+
# - 's': String
|
173
|
+
string_re = re.compile(r"%([*]?)([0-9]*)(l|)(s)")
|
174
|
+
|
175
|
+
# Constrained String Conversion
|
176
|
+
#
|
177
|
+
# Allowed Width Specifiers:
|
178
|
+
# - '': char
|
179
|
+
# - 'l': wchar_t
|
180
|
+
#
|
181
|
+
# Allowed conversions:
|
182
|
+
# - '[.*]': Constrained string; values between '[' and ']' are allowed characters.
|
183
|
+
# - '[^.*]': Constrained string; values between '[^' and ']' are forbidden characters.
|
184
|
+
|
185
|
+
# Special case to detect '%[]]' and '%[^]]'
|
186
|
+
# These will satisfy the general regexes, but will match
|
187
|
+
# on '[]' or '[^]', which isn't correct.
|
188
|
+
brace_re = re.compile(r"%([*]?)([0-9]*)(l|)\[([\^]?\])\]")
|
189
|
+
constrained_re = re.compile(r"%([*]?)([0-9]*)(l|)\[([\^]?[\]]?[^\]]*)\]")
|
190
|
+
|
191
|
+
# Pointer Conversion
|
192
|
+
#
|
193
|
+
# Allowed Width Specifiers:
|
194
|
+
# - '': void *
|
195
|
+
#
|
196
|
+
# Allowed Conversions:
|
197
|
+
# - 'p': Pointer
|
198
|
+
pointer_re = re.compile(r"%([*]?)()([0-9]*)(p)")
|
199
|
+
|
200
|
+
# Length of current input
|
201
|
+
#
|
202
|
+
# Allowed Width Specifiers
|
203
|
+
# - 'hh': char
|
204
|
+
# - 'h': short
|
205
|
+
# - '': int
|
206
|
+
# - 'l': long
|
207
|
+
# - 'll', 'L', 'q': long long
|
208
|
+
# - 'z': ssize_t
|
209
|
+
# - 'j': intmax_t
|
210
|
+
# - 't': ptrdiff_t
|
211
|
+
#
|
212
|
+
# Allowed Conversions
|
213
|
+
# - 'n': Store number of characters consumed to this point.
|
214
|
+
length_re = re.compile(r"%([*]?)(hh|h|l|ll|z|j|t|)([0-9]*)(n)")
|
215
|
+
|
216
|
+
# Percent sign
|
217
|
+
percent_re = re.compile(r"%%")
|
218
|
+
|
219
|
+
|
220
|
+
def handle_sint(
|
221
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
222
|
+
) -> bool:
|
223
|
+
flags = m.group(1)
|
224
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
225
|
+
length = m.group(3)
|
226
|
+
|
227
|
+
strval = ""
|
228
|
+
|
229
|
+
while True:
|
230
|
+
try:
|
231
|
+
char = intake.peek()
|
232
|
+
except InputEndedError:
|
233
|
+
return False
|
234
|
+
|
235
|
+
if char.isspace():
|
236
|
+
intake.pop()
|
237
|
+
else:
|
238
|
+
break
|
239
|
+
|
240
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
241
|
+
try:
|
242
|
+
char = intake.peek()
|
243
|
+
except InputEndedError:
|
244
|
+
break
|
245
|
+
|
246
|
+
if strval == "" and char in ("+", "-"):
|
247
|
+
strval += char
|
248
|
+
intake.pop()
|
249
|
+
elif char in "0123456789":
|
250
|
+
strval += char
|
251
|
+
intake.pop()
|
252
|
+
else:
|
253
|
+
break
|
254
|
+
|
255
|
+
if strval == "":
|
256
|
+
return False
|
257
|
+
|
258
|
+
if flags == "*":
|
259
|
+
intake.push(strval)
|
260
|
+
return True
|
261
|
+
|
262
|
+
intval = int(strval)
|
263
|
+
if length in ("ll", "L", "q") and intval > (2**63):
|
264
|
+
intval &= varargs._long_long_inv_mask & ~varargs._long_long_sign_mask
|
265
|
+
elif intval > (2 ** ((varargs.platdef.address_size * 8) - 1)):
|
266
|
+
intval &= varargs._long_inv_mask & ~varargs._long_sign_mask
|
267
|
+
|
268
|
+
if intval < 0:
|
269
|
+
intval *= -1
|
270
|
+
intval = (intval ^ varargs._long_long_inv_mask) + 1
|
271
|
+
|
272
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
273
|
+
|
274
|
+
assert isinstance(arg, int)
|
275
|
+
|
276
|
+
if length == "hh":
|
277
|
+
intval &= 0xFF
|
278
|
+
width = 1
|
279
|
+
elif length == "h":
|
280
|
+
intval &= 0xFFFF
|
281
|
+
width = 2
|
282
|
+
elif length == "":
|
283
|
+
intval &= varargs._int_inv_mask
|
284
|
+
width = 4
|
285
|
+
elif length in ("l", "z"):
|
286
|
+
intval &= varargs._long_inv_mask
|
287
|
+
width = 4 if ArgumentType.LONG in varargs._four_byte_types else 8
|
288
|
+
elif length in ("ll", "L", "q"):
|
289
|
+
intval &= varargs._long_long_inv_mask
|
290
|
+
width = 8
|
291
|
+
elif length == "j":
|
292
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
293
|
+
elif length == "t":
|
294
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
295
|
+
else:
|
296
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
297
|
+
|
298
|
+
if varargs.platform.byteorder == Byteorder.LITTLE:
|
299
|
+
byteval = intval.to_bytes(width, "little")
|
300
|
+
else:
|
301
|
+
byteval = intval.to_bytes(width, "big")
|
302
|
+
|
303
|
+
emulator.write_memory(arg, byteval)
|
304
|
+
|
305
|
+
return True
|
306
|
+
|
307
|
+
|
308
|
+
def handle_uint(
|
309
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
310
|
+
) -> bool:
|
311
|
+
flags = m.group(1)
|
312
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
313
|
+
length = m.group(3)
|
314
|
+
conversion = m.group(4).lower()
|
315
|
+
|
316
|
+
strval = ""
|
317
|
+
|
318
|
+
while True:
|
319
|
+
char = intake.peek()
|
320
|
+
if char.isspace():
|
321
|
+
intake.pop()
|
322
|
+
else:
|
323
|
+
break
|
324
|
+
|
325
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
326
|
+
try:
|
327
|
+
char = intake.peek()
|
328
|
+
except InputEndedError:
|
329
|
+
break
|
330
|
+
if conversion == "x" and char in ("x", "X") and strval == "0":
|
331
|
+
strval += char
|
332
|
+
intake.pop()
|
333
|
+
elif conversion == "x" and char in "0123456789abcdefABCDEF":
|
334
|
+
strval += char
|
335
|
+
intake.pop()
|
336
|
+
elif conversion == "u" and char in "0123456789":
|
337
|
+
strval += char
|
338
|
+
intake.pop()
|
339
|
+
elif conversion == "o" and char in "01234567":
|
340
|
+
strval += char
|
341
|
+
intake.pop()
|
342
|
+
else:
|
343
|
+
break
|
344
|
+
|
345
|
+
if strval == "":
|
346
|
+
return False
|
347
|
+
|
348
|
+
if flags == "*":
|
349
|
+
intake.push(strval)
|
350
|
+
return True
|
351
|
+
|
352
|
+
if conversion == "o":
|
353
|
+
intval = int(strval, 8)
|
354
|
+
elif conversion == "u":
|
355
|
+
intval = int(strval)
|
356
|
+
elif conversion == "x":
|
357
|
+
intval = int(strval, 16)
|
358
|
+
|
359
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
360
|
+
|
361
|
+
assert isinstance(arg, int)
|
362
|
+
|
363
|
+
if length == "hh":
|
364
|
+
intval &= 0xFF
|
365
|
+
width = 1
|
366
|
+
elif length == "h":
|
367
|
+
intval &= 0xFFFF
|
368
|
+
width = 2
|
369
|
+
elif length == "":
|
370
|
+
intval &= varargs._int_inv_mask
|
371
|
+
width = 4
|
372
|
+
elif length in ("l", "z"):
|
373
|
+
intval &= varargs._long_inv_mask
|
374
|
+
width = 4 if ArgumentType.LONG in varargs._four_byte_types else 8
|
375
|
+
elif length in ("ll", "L", "q"):
|
376
|
+
intval &= varargs._long_long_inv_mask
|
377
|
+
width = 8
|
378
|
+
elif length == "j":
|
379
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
380
|
+
elif length == "t":
|
381
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
382
|
+
else:
|
383
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
384
|
+
|
385
|
+
if varargs.platform.byteorder == Byteorder.LITTLE:
|
386
|
+
byteval = intval.to_bytes(width, "little")
|
387
|
+
else:
|
388
|
+
byteval = intval.to_bytes(width, "big")
|
389
|
+
emulator.write_memory(arg, byteval)
|
390
|
+
|
391
|
+
return True
|
392
|
+
|
393
|
+
|
394
|
+
def handle_float(
|
395
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
396
|
+
) -> bool:
|
397
|
+
flags = m.group(1)
|
398
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
399
|
+
length = m.group(3)
|
400
|
+
|
401
|
+
found_dot = False
|
402
|
+
found_sci = False
|
403
|
+
strval = ""
|
404
|
+
fixedval = ""
|
405
|
+
|
406
|
+
# NOTE: This will reject hexadecimal floats without a specific error.
|
407
|
+
# If _anyone_ finds a legit use of hex floats since 1999, please let me know.
|
408
|
+
# I'd be most curious to see.
|
409
|
+
|
410
|
+
while True:
|
411
|
+
try:
|
412
|
+
char = intake.peek()
|
413
|
+
except InputEndedError:
|
414
|
+
return False
|
415
|
+
|
416
|
+
if char.isspace():
|
417
|
+
intake.pop()
|
418
|
+
else:
|
419
|
+
break
|
420
|
+
|
421
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
422
|
+
try:
|
423
|
+
char = intake.peek()
|
424
|
+
except InputEndedError:
|
425
|
+
break
|
426
|
+
|
427
|
+
if "infinity".startswith(strval + char):
|
428
|
+
strval += char
|
429
|
+
intake.pop()
|
430
|
+
elif "INFINITY".startswith(strval + char):
|
431
|
+
strval += char
|
432
|
+
intake.pop()
|
433
|
+
elif "nan".startswith(strval + char):
|
434
|
+
strval += char
|
435
|
+
intake.pop()
|
436
|
+
elif "NAN".startswith(strval + char):
|
437
|
+
strval += char
|
438
|
+
intake.pop()
|
439
|
+
elif "-infinity".startswith(strval + char):
|
440
|
+
strval += char
|
441
|
+
intake.pop()
|
442
|
+
elif "-INFINITY".startswith(strval + char):
|
443
|
+
strval += char
|
444
|
+
intake.pop()
|
445
|
+
elif "-nan".startswith(strval + char):
|
446
|
+
strval += char
|
447
|
+
intake.pop()
|
448
|
+
elif "-NAN".startswith(strval + char):
|
449
|
+
strval += char
|
450
|
+
intake.pop()
|
451
|
+
elif (strval == "" or strval[-1] in ("e", "E")) and char in ("+", "-"):
|
452
|
+
strval += char
|
453
|
+
intake.pop()
|
454
|
+
elif not found_dot and not found_sci and char == ".":
|
455
|
+
found_dot = True
|
456
|
+
strval += char
|
457
|
+
intake.pop()
|
458
|
+
elif not found_sci and char in ("e", "E"):
|
459
|
+
# So, scientific notation is a pain,
|
460
|
+
# because an invalid scientific number can be prefixed by a valid fixed-point number.
|
461
|
+
# Remember what came before; we'll need to restore back to it.
|
462
|
+
found_sci = True
|
463
|
+
fixedval = strval
|
464
|
+
strval += char
|
465
|
+
intake.pop()
|
466
|
+
elif char in "0123456789":
|
467
|
+
strval += char
|
468
|
+
intake.pop()
|
469
|
+
else:
|
470
|
+
break
|
471
|
+
|
472
|
+
if strval == "":
|
473
|
+
return False
|
474
|
+
|
475
|
+
if strval[-1] in ("e", "E"):
|
476
|
+
# C accepts scientific notation with no exponent.
|
477
|
+
# Python does not.
|
478
|
+
strval += "0"
|
479
|
+
|
480
|
+
try:
|
481
|
+
floatval = float(strval)
|
482
|
+
except ValueError:
|
483
|
+
if fixedval == "":
|
484
|
+
return False
|
485
|
+
try:
|
486
|
+
intake.push(strval[len(fixedval) :])
|
487
|
+
floatval = float(fixedval)
|
488
|
+
except ValueError:
|
489
|
+
intake.push(fixedval)
|
490
|
+
return False
|
491
|
+
|
492
|
+
if flags == "*":
|
493
|
+
return True
|
494
|
+
|
495
|
+
endian = ">" if varargs.platform.byteorder == Byteorder.BIG else "<"
|
496
|
+
|
497
|
+
if length == "":
|
498
|
+
byteval = struct.pack(f"{endian}f", floatval)
|
499
|
+
elif length == "l":
|
500
|
+
byteval = struct.pack(f"{endian}d", floatval)
|
501
|
+
elif length == "L":
|
502
|
+
raise NotImplementedError("long doubles not handled")
|
503
|
+
else:
|
504
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
505
|
+
|
506
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
507
|
+
|
508
|
+
assert isinstance(arg, int)
|
509
|
+
|
510
|
+
emulator.write_memory(arg, byteval)
|
511
|
+
|
512
|
+
return True
|
513
|
+
|
514
|
+
|
515
|
+
def handle_char(
|
516
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
517
|
+
) -> bool:
|
518
|
+
flags = m.group(1)
|
519
|
+
maxwidth = 1 if m.group(2) == "" else int(m.group(2))
|
520
|
+
length = m.group(3)
|
521
|
+
|
522
|
+
if length == "l":
|
523
|
+
raise NotImplementedError("wchar_t not handled")
|
524
|
+
elif length != "":
|
525
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
526
|
+
|
527
|
+
strval = ""
|
528
|
+
|
529
|
+
while len(strval) < maxwidth:
|
530
|
+
try:
|
531
|
+
char = intake.peek()
|
532
|
+
except InputEndedError:
|
533
|
+
break
|
534
|
+
|
535
|
+
strval += char
|
536
|
+
intake.pop()
|
537
|
+
|
538
|
+
if flags == "*":
|
539
|
+
return True
|
540
|
+
|
541
|
+
byteval = strval.encode("utf-8")
|
542
|
+
|
543
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
544
|
+
|
545
|
+
assert isinstance(arg, int)
|
546
|
+
|
547
|
+
emulator.write_memory(arg, byteval)
|
548
|
+
|
549
|
+
return True
|
550
|
+
|
551
|
+
|
552
|
+
def handle_string(
|
553
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
554
|
+
) -> bool:
|
555
|
+
flags = m.group(1)
|
556
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
557
|
+
length = m.group(3)
|
558
|
+
|
559
|
+
if length == "l":
|
560
|
+
raise NotImplementedError("wchar_t not handled")
|
561
|
+
elif length != "":
|
562
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
563
|
+
|
564
|
+
strval = ""
|
565
|
+
|
566
|
+
while True:
|
567
|
+
try:
|
568
|
+
char = intake.peek()
|
569
|
+
except InputEndedError:
|
570
|
+
return False
|
571
|
+
|
572
|
+
if char.isspace():
|
573
|
+
intake.pop()
|
574
|
+
else:
|
575
|
+
break
|
576
|
+
|
577
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
578
|
+
try:
|
579
|
+
char = intake.peek()
|
580
|
+
except InputEndedError:
|
581
|
+
break
|
582
|
+
|
583
|
+
if not char.isspace():
|
584
|
+
strval += char
|
585
|
+
intake.pop()
|
586
|
+
else:
|
587
|
+
break
|
588
|
+
|
589
|
+
if flags == "*":
|
590
|
+
return True
|
591
|
+
|
592
|
+
byteval = strval.encode("utf-8")
|
593
|
+
byteval += b"\0"
|
594
|
+
|
595
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
596
|
+
|
597
|
+
assert isinstance(arg, int)
|
598
|
+
|
599
|
+
emulator.write_memory(arg, byteval)
|
600
|
+
|
601
|
+
return True
|
602
|
+
|
603
|
+
|
604
|
+
def handle_constrained(
|
605
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
606
|
+
) -> bool:
|
607
|
+
flags = m.group(1)
|
608
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
609
|
+
length = m.group(3)
|
610
|
+
conversion = m.group(4)
|
611
|
+
|
612
|
+
if length == "l":
|
613
|
+
raise NotImplementedError("wchar_t not handled")
|
614
|
+
elif length != "":
|
615
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
616
|
+
|
617
|
+
if conversion[0] == "^":
|
618
|
+
invert = True
|
619
|
+
conversion = conversion[1:]
|
620
|
+
|
621
|
+
strval = ""
|
622
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
623
|
+
try:
|
624
|
+
char = intake.peek()
|
625
|
+
except InputEndedError:
|
626
|
+
break
|
627
|
+
|
628
|
+
if invert and char not in conversion:
|
629
|
+
strval += char
|
630
|
+
intake.pop()
|
631
|
+
elif not invert and char in conversion:
|
632
|
+
strval += char
|
633
|
+
intake.pop()
|
634
|
+
else:
|
635
|
+
break
|
636
|
+
|
637
|
+
if flags == "*":
|
638
|
+
return True
|
639
|
+
|
640
|
+
byteval = strval.encode("utf-8")
|
641
|
+
byteval += b"\0"
|
642
|
+
|
643
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
644
|
+
|
645
|
+
assert isinstance(arg, int)
|
646
|
+
|
647
|
+
emulator.write_memory(arg, byteval)
|
648
|
+
|
649
|
+
return True
|
650
|
+
|
651
|
+
|
652
|
+
def handle_pointer(
|
653
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
654
|
+
) -> bool:
|
655
|
+
flags = m.group(1)
|
656
|
+
maxwidth = -1 if m.group(2) == "" else int(m.group(2))
|
657
|
+
|
658
|
+
strval = ""
|
659
|
+
|
660
|
+
while True:
|
661
|
+
try:
|
662
|
+
char = intake.peek()
|
663
|
+
except InputEndedError:
|
664
|
+
return False
|
665
|
+
|
666
|
+
if char.isspace():
|
667
|
+
intake.pop()
|
668
|
+
else:
|
669
|
+
break
|
670
|
+
|
671
|
+
while maxwidth == -1 or len(strval) < maxwidth:
|
672
|
+
try:
|
673
|
+
char = intake.peek()
|
674
|
+
except InputEndedError:
|
675
|
+
break
|
676
|
+
|
677
|
+
if (
|
678
|
+
"(nil)".startswith(strval + char)
|
679
|
+
or "(NIL)".startswith(strval + char)
|
680
|
+
or "0x".startswith(strval + char)
|
681
|
+
):
|
682
|
+
strval += char
|
683
|
+
intake.pop()
|
684
|
+
elif char in "0123456789abcdefABCDEF":
|
685
|
+
strval += char
|
686
|
+
intake.pop()
|
687
|
+
else:
|
688
|
+
break
|
689
|
+
|
690
|
+
if strval == "":
|
691
|
+
return False
|
692
|
+
|
693
|
+
if flags == "*":
|
694
|
+
intake.push(strval)
|
695
|
+
return True
|
696
|
+
|
697
|
+
if strval in ("(nil)", "(NIL)"):
|
698
|
+
intval = 0
|
699
|
+
else:
|
700
|
+
try:
|
701
|
+
intval = int(strval, 16)
|
702
|
+
except ValueError:
|
703
|
+
intake.push(strval)
|
704
|
+
return False
|
705
|
+
|
706
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
707
|
+
|
708
|
+
assert isinstance(arg, int)
|
709
|
+
|
710
|
+
if varargs.platform.byteorder == Byteorder.BIG:
|
711
|
+
byteval = intval.to_bytes(varargs.platdef.address_size, "big")
|
712
|
+
else:
|
713
|
+
byteval = intval.to_bytes(varargs.platdef.address_size, "little")
|
714
|
+
|
715
|
+
emulator.write_memory(arg, byteval)
|
716
|
+
|
717
|
+
return True
|
718
|
+
|
719
|
+
|
720
|
+
def handle_length(
|
721
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
722
|
+
) -> bool:
|
723
|
+
length = m.group(3)
|
724
|
+
|
725
|
+
intval = intake.cursor
|
726
|
+
|
727
|
+
if length == "hh":
|
728
|
+
intval &= 0xFF
|
729
|
+
width = 1
|
730
|
+
elif length == "h":
|
731
|
+
intval &= 0xFFFF
|
732
|
+
width = 2
|
733
|
+
elif length == "":
|
734
|
+
intval &= varargs._int_inv_mask
|
735
|
+
width = 4
|
736
|
+
elif length in ("l", "z"):
|
737
|
+
intval &= varargs._long_inv_mask
|
738
|
+
width = 4 if ArgumentType.LONG in varargs._four_byte_types else 8
|
739
|
+
elif length in ("ll", "L", "q"):
|
740
|
+
intval &= varargs._long_long_inv_mask
|
741
|
+
width = 8
|
742
|
+
elif length == "j":
|
743
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
744
|
+
elif length == "t":
|
745
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
746
|
+
else:
|
747
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
748
|
+
|
749
|
+
arg = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
750
|
+
|
751
|
+
assert isinstance(arg, int)
|
752
|
+
|
753
|
+
if varargs.platform.byteorder == Byteorder.BIG:
|
754
|
+
byteval = intval.to_bytes(width, "big")
|
755
|
+
else:
|
756
|
+
byteval = intval.to_bytes(width, "little")
|
757
|
+
|
758
|
+
emulator.write_memory(arg, byteval)
|
759
|
+
|
760
|
+
return True
|
761
|
+
|
762
|
+
|
763
|
+
def handle_percent(
|
764
|
+
intake: Intake, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
765
|
+
) -> bool:
|
766
|
+
return True
|
767
|
+
|
768
|
+
|
769
|
+
def handle_scanf_format(
|
770
|
+
model: CStdModel, intake: Intake, fmt: str, emulator: Emulator
|
771
|
+
) -> int:
|
772
|
+
"""Process a scanf format string
|
773
|
+
|
774
|
+
This is not an entirely complete model.
|
775
|
+
The following features are missing:
|
776
|
+
|
777
|
+
- Decoding for hexadecimal floats
|
778
|
+
- intmax_t integers
|
779
|
+
- ptrdiff_t integers
|
780
|
+
|
781
|
+
Arguments:
|
782
|
+
model: The parent API model
|
783
|
+
intake: The intake structure from which to fetch data
|
784
|
+
emulator: The emulator to run against
|
785
|
+
|
786
|
+
Returns:
|
787
|
+
The number of converted arguments, or -1, as per the scanf family.
|
788
|
+
"""
|
789
|
+
varargs = model.get_varargs()
|
790
|
+
|
791
|
+
orig_fmt = fmt
|
792
|
+
|
793
|
+
handlers = [
|
794
|
+
(sint_re, handle_sint),
|
795
|
+
(uint_re, handle_uint),
|
796
|
+
(float_re, handle_float),
|
797
|
+
(char_re, handle_char),
|
798
|
+
(string_re, handle_string),
|
799
|
+
(brace_re, handle_constrained),
|
800
|
+
(constrained_re, handle_constrained),
|
801
|
+
(pointer_re, handle_pointer),
|
802
|
+
(length_re, handle_length),
|
803
|
+
(percent_re, handle_percent),
|
804
|
+
]
|
805
|
+
|
806
|
+
converted = 0
|
807
|
+
done = False
|
808
|
+
while len(fmt) > 0:
|
809
|
+
if fmt[0] == "%":
|
810
|
+
# Conversion pattern. See if we can match
|
811
|
+
matched = False
|
812
|
+
for regex, handler in handlers:
|
813
|
+
m = regex.match(fmt)
|
814
|
+
if m is not None:
|
815
|
+
try:
|
816
|
+
if not handler(intake, varargs, m, emulator):
|
817
|
+
done = True
|
818
|
+
elif m.group(1) != "*" and m.group(4)[-1] != "n":
|
819
|
+
converted += 1
|
820
|
+
except FormatConversionError as e:
|
821
|
+
print(f"Bad format conversion: {e.args[0]}")
|
822
|
+
print(orig_fmt)
|
823
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
824
|
+
raise e
|
825
|
+
except Exception as e:
|
826
|
+
print(f"Exception processing conversion: {type(e)}: {e}")
|
827
|
+
print(orig_fmt)
|
828
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
829
|
+
raise e
|
830
|
+
fmt = fmt[len(m.group(0)) :]
|
831
|
+
matched = True
|
832
|
+
break
|
833
|
+
|
834
|
+
if not matched:
|
835
|
+
print("Bad format conversion: Unmatched conversion")
|
836
|
+
print(orig_fmt)
|
837
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
838
|
+
raise Exception("Bad format conversion")
|
839
|
+
|
840
|
+
if done:
|
841
|
+
break
|
842
|
+
|
843
|
+
elif fmt[0].isspace():
|
844
|
+
# Whitespace. Consume zero or more whitespace characters
|
845
|
+
while True:
|
846
|
+
char = intake.peek()
|
847
|
+
if char.isspace():
|
848
|
+
print("Space")
|
849
|
+
intake.pop()
|
850
|
+
else:
|
851
|
+
break
|
852
|
+
fmt = fmt[1:]
|
853
|
+
else:
|
854
|
+
# Normal character. Consume one character that's an exact match
|
855
|
+
char = intake.peek()
|
856
|
+
if char == fmt[0]:
|
857
|
+
intake.pop()
|
858
|
+
else:
|
859
|
+
return -1
|
860
|
+
|
861
|
+
return converted
|
862
|
+
|
863
|
+
|
864
|
+
__all__ = ["FileIntake", "StringIntake", "handle_scanf_format"]
|