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,915 @@
|
|
1
|
+
import re
|
2
|
+
import struct
|
3
|
+
import typing
|
4
|
+
|
5
|
+
from ....emulators import Emulator
|
6
|
+
from ....platforms import Byteorder
|
7
|
+
from ..cstd import ArgumentType, CStdModel, VariadicContext
|
8
|
+
from .utils import _emu_strlen
|
9
|
+
|
10
|
+
# Conversion specifiers:
|
11
|
+
#
|
12
|
+
# Group 1: Zero or more flags
|
13
|
+
#
|
14
|
+
# Group 2: Zero or one field width specifiers
|
15
|
+
# - '[0-9]+': Explicit width
|
16
|
+
# - '*': Next argument is an int storing the width
|
17
|
+
#
|
18
|
+
# Group 3: Zero or one precision specifiers
|
19
|
+
# - '.': Zero precision
|
20
|
+
# - '.[0-9]+': Explicit precision
|
21
|
+
# - '.*': Next argument is an int storing the width
|
22
|
+
# - NOTE: Default precision for floats is six.
|
23
|
+
#
|
24
|
+
# Group 4: Unused; part of the precision pattern
|
25
|
+
#
|
26
|
+
# Group 5: Zero or one length specifiers
|
27
|
+
#
|
28
|
+
# Group 6: Conversion ID
|
29
|
+
|
30
|
+
# Signed decimal int conversion
|
31
|
+
#
|
32
|
+
# Allowed flags:
|
33
|
+
# - '0': Justify the field with zeros
|
34
|
+
# - ' ': Add a space before a positive number
|
35
|
+
# - '-': Left-justify the field. Default is right-justify
|
36
|
+
# - '+': Always include a sign symbol
|
37
|
+
#
|
38
|
+
# Allowed lengths:
|
39
|
+
# - 'hh': char
|
40
|
+
# - 'h': short
|
41
|
+
# - '': int
|
42
|
+
# - 'l': long
|
43
|
+
# - 'll', 'q': long long
|
44
|
+
# - 'z', 'Z': ssize_t
|
45
|
+
# - 'j': intmax_t
|
46
|
+
# - 't': ptrdiff_t
|
47
|
+
#
|
48
|
+
# Allowed conversions:
|
49
|
+
# - d, i: signed decimal integer
|
50
|
+
sdecint_re = re.compile(
|
51
|
+
"%([0 \\-+]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(hh|h|l|ll|q|z|Z|j|t|)(d|i)"
|
52
|
+
)
|
53
|
+
|
54
|
+
# Unsigned decimal int conversion
|
55
|
+
#
|
56
|
+
# Allowed flags:
|
57
|
+
# - '0': Justify the field with zeros
|
58
|
+
# - '-': Left-justify the field. Default is right-justify
|
59
|
+
#
|
60
|
+
# Allowed lengths:
|
61
|
+
# - 'hh': char
|
62
|
+
# - 'h': short
|
63
|
+
# - '': int
|
64
|
+
# - 'l': long
|
65
|
+
# - 'll', 'q': long long
|
66
|
+
# - 'z', 'Z': size_t
|
67
|
+
# - 'j': intmax_t
|
68
|
+
# - 't': ptrdiff_t
|
69
|
+
#
|
70
|
+
# Allowed conversions:
|
71
|
+
# - u: unsigned decimal integer
|
72
|
+
udecint_re = re.compile(
|
73
|
+
"%([0\\-]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(hh|h|l|ll|q|z|Z|j|t|)(u)"
|
74
|
+
)
|
75
|
+
|
76
|
+
# Unsigned non-decimal int conversion
|
77
|
+
#
|
78
|
+
# Allowed flags:
|
79
|
+
# - '#': Add '0o' or '0x' prefix, as appropriate
|
80
|
+
# - '0': Justify the field with zeros
|
81
|
+
# - '-': Left-justify the field. Default is right-justify
|
82
|
+
#
|
83
|
+
# Allowed lengths:
|
84
|
+
# - 'hh': char
|
85
|
+
# - 'h': short
|
86
|
+
# - '': int
|
87
|
+
# - 'l': long
|
88
|
+
# - 'll', 'q': long long
|
89
|
+
# - 'z', 'Z': size_t
|
90
|
+
# - 'j': intmax_t
|
91
|
+
# - 't': ptrdiff_t
|
92
|
+
#
|
93
|
+
# Allowed conversions:
|
94
|
+
# - o: unsigned octal integer
|
95
|
+
# - x: unsigned hexadecimal integer, lowercase
|
96
|
+
# - X: unsigned hexadecimal integer, uppercase
|
97
|
+
uint_re = re.compile(
|
98
|
+
"%([#0\\-]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(hh|h|l|ll|q|z|Z|j|t|)(o|x|X)"
|
99
|
+
)
|
100
|
+
|
101
|
+
# Scientific notation conversion
|
102
|
+
#
|
103
|
+
# D.DDeDD
|
104
|
+
#
|
105
|
+
# Allowed flags:
|
106
|
+
# - '#': Include decimal and fractional component if zero
|
107
|
+
# - '0': Justify the field with zeros
|
108
|
+
# - ' ': Add a space before a positive number
|
109
|
+
# - '-': Left-justify the field. Default is right-justify
|
110
|
+
# - '+': Always include a sign symbol
|
111
|
+
#
|
112
|
+
# Allowed lengths
|
113
|
+
# - '': double (the compiler better damned well have gotten this right).
|
114
|
+
# - 'L': long double
|
115
|
+
#
|
116
|
+
# Allowed conversions:
|
117
|
+
# - 'e': Scientific notation, lowercase
|
118
|
+
# - 'E': Scientific notation, uppercase
|
119
|
+
sci_re = re.compile("%([#0 \\-+]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(L|)(e|E)")
|
120
|
+
|
121
|
+
# Floating point conversion
|
122
|
+
#
|
123
|
+
# DD.DD
|
124
|
+
#
|
125
|
+
# Allowed flags:
|
126
|
+
# - '#': Include decimal and fractional component if zero
|
127
|
+
# - '0': Justify the field with zeros
|
128
|
+
# - ' ': Add a space before a positive number
|
129
|
+
# - '-': Left-justify the field. Default is right-justify
|
130
|
+
# - '+': Always include a sign symbol
|
131
|
+
#
|
132
|
+
# Allowed lengths
|
133
|
+
# - '': double (the compiler better damned well have gotten this right).
|
134
|
+
# - 'L': long double
|
135
|
+
#
|
136
|
+
# Allowed conversions:
|
137
|
+
# - 'e': Floating-point, lowercase
|
138
|
+
# - 'E': Floating-point, uppercase
|
139
|
+
float_re = re.compile("%([#0 \\-+]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(L|)(f|F)")
|
140
|
+
|
141
|
+
# Size-sensitive floating point conversion
|
142
|
+
#
|
143
|
+
# DD.DD or D.DDeDD, depending on magnitude
|
144
|
+
#
|
145
|
+
# Allowed flags:
|
146
|
+
# - '#': Include decimal and fractional component if zero
|
147
|
+
# - '0': Justify the field with zeros
|
148
|
+
# - ' ': Add a space before a positive number
|
149
|
+
# - '-': Left-justify the field. Default is right-justify
|
150
|
+
# - '+': Always include a sign symbol
|
151
|
+
#
|
152
|
+
# Allowed lengths
|
153
|
+
# - '': double (the compiler better damned well have gotten this right).
|
154
|
+
# - 'L': long double
|
155
|
+
#
|
156
|
+
# Allowed conversions:
|
157
|
+
# - 'g': Floating-point, lowercase
|
158
|
+
# - 'G': Floating-point, uppercase
|
159
|
+
scifloat_re = re.compile("%([#0 \\-+]*)([0-9]*|[*])((\\.[0-9]*|\\.[*])?)(L|)(g|G)")
|
160
|
+
|
161
|
+
# Hexadecimal floating point conversion
|
162
|
+
#
|
163
|
+
# 0xXX.XX
|
164
|
+
#
|
165
|
+
# Allowed flags:
|
166
|
+
# - '#': Include decimal and fractional component if zero
|
167
|
+
# - '0': Justify the field with zeros
|
168
|
+
# - ' ': Add a space before a positive number
|
169
|
+
# - '-': Left-justify the field. Default is right-justify
|
170
|
+
# - '+': Always include a sign symbol
|
171
|
+
#
|
172
|
+
# Allowed lengths
|
173
|
+
# - '': double (the compiler better damned well have gotten this right).
|
174
|
+
# - 'L': long double
|
175
|
+
#
|
176
|
+
# Allowed conversions:
|
177
|
+
# - 'a': Hexadecimal floating-point, lowercase
|
178
|
+
# - 'A': Hexadecimal floating-point, uppercase
|
179
|
+
hexfloat_re = re.compile("%([#0 \\-+]*)([0-9]*|[*])((\\.[0-9]+|\\.[*])?)(L|)(g|G)")
|
180
|
+
|
181
|
+
# Character conversion
|
182
|
+
#
|
183
|
+
# c
|
184
|
+
#
|
185
|
+
# Allowed flags:
|
186
|
+
# - ' ': Add a space before a string
|
187
|
+
# - '-': Left-justify the field. Default is right-justify
|
188
|
+
#
|
189
|
+
# Allowed Lengths:
|
190
|
+
# - ' ': unsigned char
|
191
|
+
# - 'l': wchar_t
|
192
|
+
#
|
193
|
+
# Allowed conversions:
|
194
|
+
# - 'c': Character
|
195
|
+
char_re = re.compile("%([ \\-]*)([0-9]*|[*])()()(l|)(c)")
|
196
|
+
|
197
|
+
# String conversion
|
198
|
+
#
|
199
|
+
# cccccccc
|
200
|
+
#
|
201
|
+
# Allowed flags:
|
202
|
+
# - ' ': Add a space before a string
|
203
|
+
# - '-': Left-justify the field. Default is right-justify
|
204
|
+
#
|
205
|
+
# Allowed lengths
|
206
|
+
# - '': char *
|
207
|
+
# - 'l': wchar_t *
|
208
|
+
#
|
209
|
+
# Allowed conversions:
|
210
|
+
# - s: String
|
211
|
+
str_re = re.compile("%([ \\-]*)([0-9]*|[*])((\\.[0-9]+|\\.[*])?)(l|)(s)")
|
212
|
+
|
213
|
+
# Pointer conversion
|
214
|
+
#
|
215
|
+
# 0xXXXXXXXX
|
216
|
+
#
|
217
|
+
# Allowed flags:
|
218
|
+
# - '-': Left-justify the field.
|
219
|
+
#
|
220
|
+
# Allowed lengths:
|
221
|
+
# - '': void *
|
222
|
+
#
|
223
|
+
# Allowed conversions:
|
224
|
+
# - p: pointer
|
225
|
+
pointer_re = re.compile("%([\\-]?)([0-9]*|[*])()()()(p)")
|
226
|
+
|
227
|
+
# Length of current output
|
228
|
+
#
|
229
|
+
# <prints nothing>
|
230
|
+
#
|
231
|
+
# Allowed flags:
|
232
|
+
# - None
|
233
|
+
#
|
234
|
+
# Allowed lengths:
|
235
|
+
# - 'hh': char *
|
236
|
+
# - 'h': short *
|
237
|
+
# - '': int *
|
238
|
+
# - 'l': long *
|
239
|
+
# - 'll', 'q': long long *
|
240
|
+
# - 'z', 'Z': size_t *
|
241
|
+
# - 'j': intmax_t *
|
242
|
+
# - 't': ptrdiff_t *
|
243
|
+
#
|
244
|
+
# Allowed conversions:
|
245
|
+
# - 'n': Fetch length of current output
|
246
|
+
len_re = re.compile("%()()()()(hh|h|l|ll|q|z|Z|j|t|)(n)")
|
247
|
+
|
248
|
+
# Strerror conversion
|
249
|
+
#
|
250
|
+
# ssssssss # result of strerror(errno)
|
251
|
+
#
|
252
|
+
# Allowed flags:
|
253
|
+
# - ' ': Add a space before a string
|
254
|
+
# - '-': Left-justify the field. Default is right-justify
|
255
|
+
#
|
256
|
+
# Allowed lengths:
|
257
|
+
# - '': Default; this doesn't take an argument.
|
258
|
+
#
|
259
|
+
# Allowed conversions:
|
260
|
+
# - varargs: VariadicContext, m: strerror
|
261
|
+
strerror_re = re.compile("%([ \\-]*)([0-9]*|[*])()()()(m)")
|
262
|
+
|
263
|
+
# Percent sign
|
264
|
+
#
|
265
|
+
# %
|
266
|
+
#
|
267
|
+
# Allowed flags:
|
268
|
+
# - None
|
269
|
+
#
|
270
|
+
# Allowed lengths:
|
271
|
+
# - None
|
272
|
+
#
|
273
|
+
# Allowed conversions:
|
274
|
+
# - '%': Print a literal '%'
|
275
|
+
percent_re = re.compile("%%")
|
276
|
+
|
277
|
+
|
278
|
+
class FormatConversionError(Exception):
|
279
|
+
pass
|
280
|
+
|
281
|
+
|
282
|
+
def handle_flags(flags: str) -> str:
|
283
|
+
out = ""
|
284
|
+
if "-" in flags:
|
285
|
+
out += "<"
|
286
|
+
else:
|
287
|
+
out += ">"
|
288
|
+
|
289
|
+
if "+" in flags:
|
290
|
+
out += "+"
|
291
|
+
|
292
|
+
if " " in flags:
|
293
|
+
out += " "
|
294
|
+
|
295
|
+
if "0" in flags:
|
296
|
+
out += "0"
|
297
|
+
|
298
|
+
if "#" in flags:
|
299
|
+
out += "#"
|
300
|
+
|
301
|
+
return out
|
302
|
+
|
303
|
+
|
304
|
+
def handle_width(width: str, varargs: VariadicContext, emulator: Emulator) -> str:
|
305
|
+
if width == "*":
|
306
|
+
width_int = varargs.get_next_argument(ArgumentType.INT, emulator)
|
307
|
+
assert isinstance(width_int, int)
|
308
|
+
return str(width_int)
|
309
|
+
else:
|
310
|
+
return width
|
311
|
+
|
312
|
+
|
313
|
+
def handle_precision(
|
314
|
+
precision: str, varargs: VariadicContext, emulator: Emulator, use_default=True
|
315
|
+
) -> str:
|
316
|
+
if precision == ".*":
|
317
|
+
precision_int = varargs.get_next_argument(ArgumentType.INT, emulator)
|
318
|
+
assert isinstance(precision_int, int)
|
319
|
+
return "." + str(precision_int)
|
320
|
+
elif precision == ".":
|
321
|
+
return ".0"
|
322
|
+
elif precision == "":
|
323
|
+
if use_default:
|
324
|
+
return ".6"
|
325
|
+
else:
|
326
|
+
return ""
|
327
|
+
else:
|
328
|
+
return precision
|
329
|
+
|
330
|
+
|
331
|
+
def handle_double_arg(
|
332
|
+
length: str, varargs: VariadicContext, emulator: Emulator
|
333
|
+
) -> float:
|
334
|
+
if length == "":
|
335
|
+
val = varargs.get_next_argument(ArgumentType.DOUBLE, emulator)
|
336
|
+
elif length == "L":
|
337
|
+
raise NotImplementedError("Type 'long double' not handled")
|
338
|
+
else:
|
339
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
340
|
+
assert isinstance(val, float)
|
341
|
+
return val
|
342
|
+
|
343
|
+
|
344
|
+
def handle_sdecint(
|
345
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
346
|
+
) -> str:
|
347
|
+
flags = m.group(1)
|
348
|
+
width = m.group(2)
|
349
|
+
precision = m.group(3)
|
350
|
+
length = m.group(5)
|
351
|
+
# Conversion is irrelevant; they're aliases for the same thing.
|
352
|
+
|
353
|
+
fmt = "{:"
|
354
|
+
|
355
|
+
# Handle flags
|
356
|
+
# These mean the same for python as they do for C,
|
357
|
+
# with the exception of '-' in C being '<' in Python
|
358
|
+
flags = handle_flags(flags)
|
359
|
+
fmt += flags
|
360
|
+
|
361
|
+
# Handle width
|
362
|
+
width = handle_width(width, varargs, emulator)
|
363
|
+
fmt += width
|
364
|
+
|
365
|
+
# Handle precision
|
366
|
+
# Precision in ints acts like a second width,
|
367
|
+
# which always has the '0' flag enabled.
|
368
|
+
# This isn't implemented in python, which means we need to do it piecewise
|
369
|
+
if precision != "":
|
370
|
+
raise NotImplementedError("TODO: Implemente precision for ints")
|
371
|
+
|
372
|
+
# Handle length
|
373
|
+
if length in ("hh", "h", ""):
|
374
|
+
# Variadics don't go smaller than 'int'
|
375
|
+
val = varargs.get_next_argument(ArgumentType.INT, emulator)
|
376
|
+
elif length == "l":
|
377
|
+
val = varargs.get_next_argument(ArgumentType.LONG, emulator)
|
378
|
+
elif length in ("ll", "q"):
|
379
|
+
val = varargs.get_next_argument(ArgumentType.LONGLONG, emulator)
|
380
|
+
elif length in ("z", "Z"):
|
381
|
+
val = varargs.get_next_argument(ArgumentType.SSIZE_T, emulator)
|
382
|
+
elif length == "j":
|
383
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
384
|
+
elif length == "t":
|
385
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
386
|
+
else:
|
387
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
388
|
+
|
389
|
+
assert isinstance(val, int)
|
390
|
+
|
391
|
+
fmt += "d}"
|
392
|
+
|
393
|
+
return fmt.format(val)
|
394
|
+
|
395
|
+
|
396
|
+
def handle_udecint(
|
397
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
398
|
+
) -> str:
|
399
|
+
flags = m.group(1)
|
400
|
+
width = m.group(2)
|
401
|
+
precision = m.group(3)
|
402
|
+
length = m.group(5)
|
403
|
+
# Conversion is irrelevant; they're aliases for the same thing.
|
404
|
+
|
405
|
+
fmt = "{:"
|
406
|
+
|
407
|
+
# Handle flags
|
408
|
+
# These mean the same for python as they do for C,
|
409
|
+
# with the exception of '-' in C being '<' in Python
|
410
|
+
flags = handle_flags(flags)
|
411
|
+
fmt += flags
|
412
|
+
|
413
|
+
# Handle width
|
414
|
+
width = handle_width(width, varargs, emulator)
|
415
|
+
fmt += width
|
416
|
+
|
417
|
+
# Handle precision
|
418
|
+
# Precision in ints acts like a second width,
|
419
|
+
# which always has the '0' flag enabled.
|
420
|
+
# This isn't implemented in python, which means we need to do it piecewise
|
421
|
+
if precision != "":
|
422
|
+
raise NotImplementedError("TODO: Implemente precision for ints")
|
423
|
+
|
424
|
+
# Handle length
|
425
|
+
if length in ("hh", "h", ""):
|
426
|
+
# Variadics don't go smaller than 'int'
|
427
|
+
val = varargs.get_next_argument(ArgumentType.UINT, emulator)
|
428
|
+
elif length == "l":
|
429
|
+
val = varargs.get_next_argument(ArgumentType.ULONG, emulator)
|
430
|
+
elif length in ("ll", "q"):
|
431
|
+
val = varargs.get_next_argument(ArgumentType.ULONGLONG, emulator)
|
432
|
+
elif length in ("z", "Z"):
|
433
|
+
val = varargs.get_next_argument(ArgumentType.SIZE_T, emulator)
|
434
|
+
elif length == "j":
|
435
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
436
|
+
elif length == "t":
|
437
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
438
|
+
else:
|
439
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
440
|
+
assert isinstance(val, int)
|
441
|
+
|
442
|
+
fmt += "d}"
|
443
|
+
|
444
|
+
return fmt.format(val)
|
445
|
+
|
446
|
+
|
447
|
+
def handle_uint(
|
448
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
449
|
+
) -> str:
|
450
|
+
flags = m.group(1)
|
451
|
+
width = m.group(2)
|
452
|
+
precision = m.group(3)
|
453
|
+
length = m.group(5)
|
454
|
+
conv = m.group(6)
|
455
|
+
|
456
|
+
# Handle flags
|
457
|
+
# These mean the same for python as they do for C,
|
458
|
+
# with the exception of '-' in C being '<' in Python
|
459
|
+
flags = handle_flags(flags)
|
460
|
+
# In C, octals can have both '#' and '0' flags.
|
461
|
+
# In practice, the '#' is redundant, and forbidden by Python
|
462
|
+
if "0" in flags:
|
463
|
+
flags = flags.replace("#", "")
|
464
|
+
|
465
|
+
# Handle width
|
466
|
+
width = handle_width(width, varargs, emulator)
|
467
|
+
|
468
|
+
# Handle precision
|
469
|
+
# Precision in ints acts like a second width,
|
470
|
+
# which always has the '0' flag enabled.
|
471
|
+
# This isn't implemented in python, which means we need to do it piecewise
|
472
|
+
if precision != "":
|
473
|
+
raise NotImplementedError("TODO: Implemente precision for ints")
|
474
|
+
|
475
|
+
# Handle length
|
476
|
+
if length in ("hh", "h", ""):
|
477
|
+
# Variadics don't go smaller than 'int'
|
478
|
+
val = varargs.get_next_argument(ArgumentType.UINT, emulator)
|
479
|
+
elif length == "l":
|
480
|
+
val = varargs.get_next_argument(ArgumentType.ULONG, emulator)
|
481
|
+
elif length in ("ll", "q"):
|
482
|
+
val = varargs.get_next_argument(ArgumentType.ULONGLONG, emulator)
|
483
|
+
elif length in ("z", "Z"):
|
484
|
+
val = varargs.get_next_argument(ArgumentType.SIZE_T, emulator)
|
485
|
+
elif length == "j":
|
486
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
487
|
+
elif length == "t":
|
488
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
489
|
+
else:
|
490
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
491
|
+
|
492
|
+
assert isinstance(val, int)
|
493
|
+
|
494
|
+
fmt = "{:"
|
495
|
+
fmt += flags
|
496
|
+
fmt += width
|
497
|
+
fmt += conv
|
498
|
+
fmt += "}"
|
499
|
+
res = fmt.format(val)
|
500
|
+
if "#" in flags and conv == "o":
|
501
|
+
if width != "":
|
502
|
+
int_width = int(width)
|
503
|
+
else:
|
504
|
+
int_width = 0
|
505
|
+
extend = len(res) == int_width
|
506
|
+
res = res.replace("0o", "0")
|
507
|
+
if extend:
|
508
|
+
res = " " + res
|
509
|
+
|
510
|
+
return res
|
511
|
+
|
512
|
+
|
513
|
+
def handle_sci(
|
514
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
515
|
+
) -> str:
|
516
|
+
flags = m.group(1)
|
517
|
+
width = m.group(2)
|
518
|
+
precision = m.group(3)
|
519
|
+
length = m.group(5)
|
520
|
+
conv = m.group(6)
|
521
|
+
|
522
|
+
fmt = "{:"
|
523
|
+
|
524
|
+
# Handle flags
|
525
|
+
# These mean the same for python as they do for C,
|
526
|
+
# with the exception of '-' in C being '<' in Python
|
527
|
+
flags = handle_flags(flags)
|
528
|
+
fmt += flags
|
529
|
+
|
530
|
+
# Handle width
|
531
|
+
width = handle_width(width, varargs, emulator)
|
532
|
+
fmt += width
|
533
|
+
|
534
|
+
# Handle precision
|
535
|
+
precision = handle_precision(precision, varargs, emulator)
|
536
|
+
fmt += precision
|
537
|
+
|
538
|
+
# Handle length
|
539
|
+
val = handle_double_arg(length, varargs, emulator)
|
540
|
+
|
541
|
+
fmt += conv
|
542
|
+
fmt += "}"
|
543
|
+
|
544
|
+
out = fmt.format(val)
|
545
|
+
|
546
|
+
# Handle negative NaN.
|
547
|
+
# Python prints it as positive NaN.
|
548
|
+
byteval = struct.pack("<d", val)
|
549
|
+
intval = int.from_bytes(byteval, "little")
|
550
|
+
if intval == 0xFFF8000000000000:
|
551
|
+
text = ("{:" + conv + "}").format(val)
|
552
|
+
index = out.index(text)
|
553
|
+
if index == 0:
|
554
|
+
out = out.replace(text, "-" + text)
|
555
|
+
else:
|
556
|
+
out = out[: index - 1] + "-" + text + out[index + 3 :]
|
557
|
+
|
558
|
+
return out
|
559
|
+
|
560
|
+
|
561
|
+
def handle_float(
|
562
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
563
|
+
) -> str:
|
564
|
+
flags = m.group(1)
|
565
|
+
width = m.group(2)
|
566
|
+
precision = m.group(3)
|
567
|
+
length = m.group(5)
|
568
|
+
conv = m.group(6)
|
569
|
+
|
570
|
+
fmt = "{:"
|
571
|
+
|
572
|
+
# Handle flags
|
573
|
+
# These mean the same for python as they do for C,
|
574
|
+
# with the exception of '-' in C being '<' in Python
|
575
|
+
flags = handle_flags(flags)
|
576
|
+
fmt += flags
|
577
|
+
|
578
|
+
# Handle width
|
579
|
+
width = handle_width(width, varargs, emulator)
|
580
|
+
fmt += width
|
581
|
+
|
582
|
+
# Handle precision
|
583
|
+
precision = handle_precision(precision, varargs, emulator)
|
584
|
+
fmt += precision
|
585
|
+
|
586
|
+
# Handle length
|
587
|
+
val = handle_double_arg(length, varargs, emulator)
|
588
|
+
|
589
|
+
fmt += conv
|
590
|
+
fmt += "}"
|
591
|
+
|
592
|
+
out = fmt.format(val)
|
593
|
+
|
594
|
+
# Handle negative NaN.
|
595
|
+
# Python prints it as positive NaN.
|
596
|
+
byteval = struct.pack("<d", val)
|
597
|
+
intval = int.from_bytes(byteval, "little")
|
598
|
+
if intval == 0xFFF8000000000000:
|
599
|
+
text = ("{:" + conv + "}").format(val)
|
600
|
+
index = out.index(text)
|
601
|
+
if index == 0:
|
602
|
+
out = out.replace(text, "-" + text)
|
603
|
+
else:
|
604
|
+
out = out[: index - 1] + "-" + text + out[index + 3 :]
|
605
|
+
|
606
|
+
return out
|
607
|
+
|
608
|
+
|
609
|
+
def handle_scifloat(
|
610
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
611
|
+
) -> str:
|
612
|
+
flags = m.group(1)
|
613
|
+
width = m.group(2)
|
614
|
+
precision = m.group(3)
|
615
|
+
length = m.group(5)
|
616
|
+
conv = m.group(6)
|
617
|
+
|
618
|
+
fmt = "{:"
|
619
|
+
|
620
|
+
# Handle flags
|
621
|
+
# These mean the same for python as they do for C,
|
622
|
+
# with the exception of '-' in C being '<' in Python
|
623
|
+
flags = handle_flags(flags)
|
624
|
+
fmt += flags
|
625
|
+
|
626
|
+
# Handle width
|
627
|
+
width = handle_width(width, varargs, emulator)
|
628
|
+
fmt += width
|
629
|
+
|
630
|
+
# Handle precision
|
631
|
+
precision = handle_precision(precision, varargs, emulator)
|
632
|
+
fmt += precision
|
633
|
+
|
634
|
+
# Handle length
|
635
|
+
val = handle_double_arg(length, varargs, emulator)
|
636
|
+
|
637
|
+
fmt += conv
|
638
|
+
fmt += "}"
|
639
|
+
|
640
|
+
out = fmt.format(val)
|
641
|
+
|
642
|
+
# Handle negative NaN.
|
643
|
+
# Python prints it as positive NaN.
|
644
|
+
byteval = struct.pack("<d", val)
|
645
|
+
intval = int.from_bytes(byteval, "little")
|
646
|
+
|
647
|
+
if intval == 0xFFF8000000000000:
|
648
|
+
text = ("{:" + conv + "}").format(val)
|
649
|
+
index = out.index(text)
|
650
|
+
if index == 0:
|
651
|
+
out = out.replace(text, "-" + text)
|
652
|
+
else:
|
653
|
+
out = out[: index - 1] + "-" + text + out[index + 3 :]
|
654
|
+
|
655
|
+
return out
|
656
|
+
|
657
|
+
|
658
|
+
def handle_hexfloat(
|
659
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
660
|
+
) -> str:
|
661
|
+
# Python doesn't have an easy conversion for hex floats
|
662
|
+
# And I am not writing one unless you absolutely need it.
|
663
|
+
raise NotImplementedError("Hexadecimal float conversion not supported")
|
664
|
+
|
665
|
+
|
666
|
+
def handle_char(
|
667
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
668
|
+
) -> str:
|
669
|
+
flags = m.group(1)
|
670
|
+
width = m.group(2)
|
671
|
+
length = m.group(5)
|
672
|
+
conv = m.group(6)
|
673
|
+
|
674
|
+
fmt = "{:"
|
675
|
+
|
676
|
+
# Handle flags
|
677
|
+
# These mean the same for python as they do for C,
|
678
|
+
# with the exception of '-' in C being '<' in Python
|
679
|
+
flags = handle_flags(flags)
|
680
|
+
|
681
|
+
# Handle width
|
682
|
+
width = handle_width(width, varargs, emulator)
|
683
|
+
fmt += width
|
684
|
+
|
685
|
+
# Handle length
|
686
|
+
if length == "":
|
687
|
+
val = varargs.get_next_argument(ArgumentType.UINT, emulator)
|
688
|
+
elif length == "l":
|
689
|
+
raise NotImplementedError("Type 'wchar_t' not handled")
|
690
|
+
else:
|
691
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
692
|
+
|
693
|
+
assert isinstance(val, int)
|
694
|
+
val = val & 0xFF
|
695
|
+
|
696
|
+
fmt += conv
|
697
|
+
fmt += "}"
|
698
|
+
|
699
|
+
return fmt.format(val)
|
700
|
+
|
701
|
+
|
702
|
+
def handle_str(
|
703
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
704
|
+
) -> str:
|
705
|
+
flags = m.group(1)
|
706
|
+
width = m.group(2)
|
707
|
+
precision = m.group(3)
|
708
|
+
length = m.group(5)
|
709
|
+
conv = m.group(6)
|
710
|
+
|
711
|
+
fmt = "{:"
|
712
|
+
|
713
|
+
# Handle flags
|
714
|
+
# These mean the same for python as they do for C,
|
715
|
+
# with the exception of '-' in C being '<' in Python
|
716
|
+
flags = handle_flags(flags)
|
717
|
+
fmt += flags
|
718
|
+
|
719
|
+
# Handle width
|
720
|
+
width = handle_width(width, varargs, emulator)
|
721
|
+
fmt += width
|
722
|
+
|
723
|
+
# Handle precision
|
724
|
+
# Highly fortunately, this works the same in python
|
725
|
+
precision = handle_precision(precision, varargs, emulator, use_default=False)
|
726
|
+
fmt += precision
|
727
|
+
|
728
|
+
# Handle length
|
729
|
+
if length == "":
|
730
|
+
addr = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
731
|
+
elif length == "l":
|
732
|
+
raise NotImplementedError("Type 'wchar_t *' not handled")
|
733
|
+
else:
|
734
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
735
|
+
|
736
|
+
assert isinstance(addr, int)
|
737
|
+
|
738
|
+
val_len = _emu_strlen(emulator, addr)
|
739
|
+
val_bytes = emulator.read_memory(addr, val_len)
|
740
|
+
val = val_bytes.decode("utf-8")
|
741
|
+
|
742
|
+
fmt += conv
|
743
|
+
fmt += "}"
|
744
|
+
|
745
|
+
return fmt.format(val)
|
746
|
+
|
747
|
+
|
748
|
+
def handle_pointer(
|
749
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
750
|
+
) -> str:
|
751
|
+
flags = m.group(1)
|
752
|
+
width = m.group(2)
|
753
|
+
|
754
|
+
fmt = "{:"
|
755
|
+
|
756
|
+
# Handle flags
|
757
|
+
# These mean the same for python as they do for C,
|
758
|
+
# with the exception of '-' in C being '<' in Python
|
759
|
+
flags = handle_flags(flags)
|
760
|
+
fmt += flags + "#"
|
761
|
+
|
762
|
+
# Handle width
|
763
|
+
width = handle_width(width, varargs, emulator)
|
764
|
+
fmt += width
|
765
|
+
|
766
|
+
val = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
767
|
+
assert isinstance(val, int)
|
768
|
+
|
769
|
+
fmt += "x}"
|
770
|
+
|
771
|
+
return fmt.format(val)
|
772
|
+
|
773
|
+
|
774
|
+
def handle_len(
|
775
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
776
|
+
) -> str:
|
777
|
+
length = m.group(5)
|
778
|
+
|
779
|
+
addr = varargs.get_next_argument(ArgumentType.POINTER, emulator)
|
780
|
+
assert isinstance(addr, int)
|
781
|
+
|
782
|
+
val = len(output)
|
783
|
+
if length == "hh":
|
784
|
+
val = val & 0xFF
|
785
|
+
width = 1
|
786
|
+
elif length == "h":
|
787
|
+
val = val & 0xFFFF
|
788
|
+
width = 2
|
789
|
+
elif length == "":
|
790
|
+
val = val & varargs._int_inv_mask
|
791
|
+
width = 4
|
792
|
+
elif length in ("l", "z", "Z"):
|
793
|
+
val = val & varargs._long_inv_mask
|
794
|
+
width = 4 if ArgumentType.LONG in varargs._four_byte_types else 8
|
795
|
+
elif length in ("ll", "q"):
|
796
|
+
val = val & varargs._long_long_inv_mask
|
797
|
+
width = 8
|
798
|
+
elif length == "j":
|
799
|
+
raise NotImplementedError("Type 'intmax_t' not handled")
|
800
|
+
elif length == "t":
|
801
|
+
raise NotImplementedError("Type 'ptrdiff_t' not handled")
|
802
|
+
else:
|
803
|
+
raise FormatConversionError(f"Unknown type specifier {length}")
|
804
|
+
|
805
|
+
if varargs.platform.byteorder == Byteorder.LITTLE:
|
806
|
+
data = val.to_bytes(width, "little")
|
807
|
+
else:
|
808
|
+
data = val.to_bytes(width, "big")
|
809
|
+
|
810
|
+
emulator.write_memory(addr, data)
|
811
|
+
|
812
|
+
return ""
|
813
|
+
|
814
|
+
|
815
|
+
def handle_strerror(
|
816
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
817
|
+
) -> str:
|
818
|
+
# This is weird. It's a glibc extension, but gcc errors if you use it.
|
819
|
+
# If you actually see this, please open a bug ticket.
|
820
|
+
raise NotImplementedError(
|
821
|
+
"%m conversion (strerror) not implemented; if you see this, submit a ticket."
|
822
|
+
)
|
823
|
+
|
824
|
+
|
825
|
+
def handle_percent(
|
826
|
+
output: str, varargs: VariadicContext, m: re.Match, emulator: Emulator
|
827
|
+
) -> str:
|
828
|
+
# If this has any configurable options, I will be most displeased.
|
829
|
+
return "%"
|
830
|
+
|
831
|
+
|
832
|
+
def parse_printf_format(model: CStdModel, fmt: str, emulator: Emulator) -> str:
|
833
|
+
"""Create a string based on a printf format
|
834
|
+
|
835
|
+
This doesn't model all features of the printf family.
|
836
|
+
The following features are missing:
|
837
|
+
|
838
|
+
- The %a and %A hexadecimal float conversions
|
839
|
+
- The %m strerror conversion
|
840
|
+
- intmax_t integer size
|
841
|
+
- ptrdiff_t integer size
|
842
|
+
- long double float size
|
843
|
+
|
844
|
+
Arguments:
|
845
|
+
model: The parent model
|
846
|
+
fmt: The format string
|
847
|
+
emulator: The emulator to query
|
848
|
+
|
849
|
+
Returns:
|
850
|
+
A string formatted according to 'fmt'
|
851
|
+
"""
|
852
|
+
handlers: typing.List[
|
853
|
+
typing.Tuple[
|
854
|
+
re.Pattern, typing.Callable[[str, VariadicContext, re.Match, Emulator], str]
|
855
|
+
]
|
856
|
+
] = [
|
857
|
+
(sdecint_re, handle_sdecint),
|
858
|
+
(udecint_re, handle_udecint),
|
859
|
+
(uint_re, handle_uint),
|
860
|
+
(sci_re, handle_sci),
|
861
|
+
(float_re, handle_float),
|
862
|
+
(scifloat_re, handle_scifloat),
|
863
|
+
(hexfloat_re, handle_hexfloat),
|
864
|
+
(char_re, handle_char),
|
865
|
+
(str_re, handle_str),
|
866
|
+
(pointer_re, handle_pointer),
|
867
|
+
(len_re, handle_len),
|
868
|
+
(strerror_re, handle_strerror),
|
869
|
+
(percent_re, handle_percent),
|
870
|
+
]
|
871
|
+
|
872
|
+
varargs = model.get_varargs()
|
873
|
+
|
874
|
+
orig_fmt = fmt
|
875
|
+
output = ""
|
876
|
+
|
877
|
+
while len(fmt) > 0:
|
878
|
+
if fmt.startswith("%"):
|
879
|
+
matched = False
|
880
|
+
for regex, handler in handlers:
|
881
|
+
if isinstance(regex, str):
|
882
|
+
raise Exception(f"String: {regex}")
|
883
|
+
m = regex.match(fmt)
|
884
|
+
if m is not None:
|
885
|
+
try:
|
886
|
+
output += handler(output, varargs, m, emulator)
|
887
|
+
except FormatConversionError as e:
|
888
|
+
print(f"Bad format conversion: {e.args[0]}")
|
889
|
+
print(orig_fmt)
|
890
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
891
|
+
raise e
|
892
|
+
except Exception as e:
|
893
|
+
print(f"Exception processing conversion: {type(e)}: {e}")
|
894
|
+
print(orig_fmt)
|
895
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
896
|
+
raise e
|
897
|
+
|
898
|
+
fmt = fmt[len(m.group(0)) :]
|
899
|
+
matched = True
|
900
|
+
break
|
901
|
+
|
902
|
+
if not matched:
|
903
|
+
print("Bad format conversion: Unmatched conversion")
|
904
|
+
print(orig_fmt)
|
905
|
+
print(" " * (len(orig_fmt) - len(fmt)) + "^")
|
906
|
+
raise Exception("Bad format conversion")
|
907
|
+
|
908
|
+
else:
|
909
|
+
output += fmt[0]
|
910
|
+
fmt = fmt[1:]
|
911
|
+
|
912
|
+
return output
|
913
|
+
|
914
|
+
|
915
|
+
__all__ = ["parse_printf_format"]
|