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