From 9539d50d497dbef0c490b0e621330ea68aad5efa Mon Sep 17 00:00:00 2001 From: OBarronCS <55004530+OBarronCS@users.noreply.github.com> Date: Wed, 30 Apr 2025 08:48:56 -0700 Subject: [PATCH] Switch to Zig for cross-architecture compiling (#2935) * Use Zig for compiling for cross architecture tests. * comments/typos * Check if GDB supports crossarch targets, inline _start definition in assembly, add comments --- setup-dev.sh | 9 +- tests/qemu-tests/conftest.py | 124 ++++-- tests/qemu-tests/tests/user/binaries/Makefile | 78 ++-- tests/qemu-tests/tests/user/test_aarch64.py | 296 +++++++------ tests/qemu-tests/tests/user/test_arm.py | 390 +++++++++--------- tests/qemu-tests/tests/user/test_basic.py | 17 +- tests/qemu-tests/tests/user/test_mips.py | 255 ++++++------ tests/qemu-tests/tests/user/test_riscv64.py | 120 +++--- tests/tests.py | 27 +- 9 files changed, 743 insertions(+), 573 deletions(-) diff --git a/setup-dev.sh b/setup-dev.sh index be73a1b46..d17baa373 100755 --- a/setup-dev.sh +++ b/setup-dev.sh @@ -140,16 +140,9 @@ install_apt() { gdb \ gdb-multiarch \ parallel \ - iproute2 \ qemu-system-x86 \ qemu-system-arm \ - qemu-user \ - gcc-aarch64-linux-gnu \ - gcc-riscv64-linux-gnu \ - gcc-arm-linux-gnueabihf \ - gcc-mips-linux-gnu \ - gcc-mipsel-linux-gnu \ - gcc-mips64-linux-gnuabi64 + qemu-user # Some tests require i386 libc/ld, eg: test_smallbins_sizes_32bit_big if uname -m | grep -q x86_64; then diff --git a/tests/qemu-tests/conftest.py b/tests/qemu-tests/conftest.py index 9ba25a724..8fc2d84ef 100644 --- a/tests/qemu-tests/conftest.py +++ b/tests/qemu-tests/conftest.py @@ -7,17 +7,56 @@ from __future__ import annotations import os import subprocess import sys +import typing +from typing import Dict from typing import Literal +from typing import Tuple import gdb import pytest -from pwn import context -from pwn import make_elf_from_assembly -from pwn import pwnlib + +from pwndbg.lib import tempfile _start_binary_called = False QEMU_PORT = os.environ.get("QEMU_PORT") +ZIGPATH = os.environ.get("ZIGPATH") + +COMPILATION_TARGETS_TYPE = Literal[ + "aarch64", + "arm", + "riscv32", + "riscv64", + "loongarch64", + "powerpc32", + "powerpc64", + "mips32", + "mipsel32", + "mips64", + "s390x", + "sparc", +] + +COMPILATION_TARGETS: list[COMPILATION_TARGETS_TYPE] = list( + typing.get_args(COMPILATION_TARGETS_TYPE) +) + +# Tuple contains (Zig target,extra_cli_args,qemu_suffix), +COMPILE_AND_RUN_INFO: Dict[COMPILATION_TARGETS_TYPE, Tuple[str, Tuple[str, ...], str]] = { + "aarch64": ("aarch64-freestanding", (), "aarch64"), + # TODO: when updating to newer version of Zig, this -mcpu option can be removed + "arm": ("arm-freestanding", ("-mcpu=cortex_a7",), "arm"), + "riscv32": ("riscv32-freestanding", (), "riscv32"), + "riscv64": ("riscv64-freestanding", (), "riscv64"), + "mips32": ("mips-freestanding", (), "mips"), + "mipsel32": ("mipsel-freestanding", (), "mipsel"), + "mips64": ("mips64-freestanding", (), "mips64"), + "loongarch64": ("loongarch64-freestanding", (), "loongarch64"), + "s390x": ("s390x-freestanding", (), "s390x"), + "sparc": ("sparc64-freestanding", (), "sparc64"), + "powerpc32": ("powerpc-freestanding", (), "ppc"), + "powerpc64": ("powerpc64-freestanding", (), "ppc64"), +} @pytest.fixture @@ -28,32 +67,62 @@ def qemu_assembly_run(): The `path` is returned from `make_elf_from_assembly` (provided by pwntools) """ + if ZIGPATH is None: + raise Exception("ZIGPATH not defined") + + PATH_TO_ZIG = os.path.join(ZIGPATH, "zig") + qemu: subprocess.Popen = None if QEMU_PORT is None: print("'QEMU_PORT' environment variable not set") sys.exit(1) - def _start_binary(asm: str, arch: str, endian: Literal["big", "little"] | None = None): + def _start_binary(asm: str, arch: COMPILATION_TARGETS_TYPE): nonlocal qemu - # Clear the context so setting the .arch will also set .bits - # https://github.com/Gallopsled/pwntools/issues/2498 - context.clear() - context.arch = arch + if arch not in COMPILATION_TARGETS or arch not in COMPILE_AND_RUN_INFO: + raise Exception(f"Unknown compilation target: {arch}") - if endian is not None: - context.endian = endian + zig_target, extra_cli_args, qemu_suffix = COMPILE_AND_RUN_INFO[arch] - binary_tmp_path = make_elf_from_assembly(asm) - qemu_suffix = pwnlib.qemu.archname() + # Place assembly and compiled binary in a temporary folder + # named /tmp/pwndbg-* + tmpdir = tempfile.tempdir() + + asm_file = os.path.join(tmpdir, "input.S") + + with open(asm_file, "w") as f: + f.write(asm) + + compiled_file = os.path.join(tmpdir, "out.elf") + + # Build the binary with Zig + compile_process = subprocess.run( + [ + PATH_TO_ZIG, + "cc", + *extra_cli_args, + f"--target={zig_target}", + asm_file, + "-o", + compiled_file, + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + + if compile_process.returncode != 0: + raise Exception("Compilation error", compile_process.stdout, compile_process.stderr) qemu = subprocess.Popen( [ f"qemu-{qemu_suffix}", "-g", f"{QEMU_PORT}", - f"{binary_tmp_path}", + f"{compiled_file}", ] ) @@ -75,21 +144,6 @@ def qemu_assembly_run(): qemu.kill() -# Map of qemu_suffix to location of library files in default Ubuntu installs of cross-compilers -CROSS_ARCH_LIBC = { - "aarch64": "/usr/aarch64-linux-gnu", - "arm": "/usr/arm-linux-gnueabihf", - "mips": "/usr/mips-linux-gnu", - "mipsel": "/usr/mipsel-linux-gnu", - "mips64": "/usr/mips64-linux-gnuabi64/", - "riscv64": "/usr/riscv64-linux-gnu/", - "loongarch64": "/usr/loongarch64-linux-gnu/", - "ppc": "/usr/powerpc-linux-gnu/", - "ppc64": "/usr/powerpc64-linux-gnu/", - "sparc64": "/usr/sparc64-linux-gnu/", -} - - @pytest.fixture def qemu_start_binary(): """ @@ -104,23 +158,17 @@ def qemu_start_binary(): print("'QEMU_PORT' environment variable not set") sys.exit(1) - def _start_binary(path: str, arch: str, endian: Literal["big", "little"] | None = None): + def _start_binary(path: str, arch: COMPILATION_TARGETS_TYPE): nonlocal qemu - if endian is not None: - context.endian = endian - - qemu_suffix = pwnlib.qemu.archname(arch=arch) - # qemu_libs = pwnlib.qemu.ld_prefix(arch=arch) - qemu_libs = CROSS_ARCH_LIBC.get(qemu_suffix, f"/usr/gnemul/qemu-{qemu_suffix}") + if arch not in COMPILATION_TARGETS or arch not in COMPILE_AND_RUN_INFO: + raise Exception(f"Unknown compilation target: {arch}") - assert os.path.isdir(qemu_libs), f"Cannot find cross-arch libraries at path: {qemu_libs}" + _, _, qemu_suffix = COMPILE_AND_RUN_INFO[arch] qemu = subprocess.Popen( [ f"qemu-{qemu_suffix}", - "-L", - qemu_libs, "-g", f"{QEMU_PORT}", f"{path}", diff --git a/tests/qemu-tests/tests/user/binaries/Makefile b/tests/qemu-tests/tests/user/binaries/Makefile index ade2d113d..2b9e44674 100644 --- a/tests/qemu-tests/tests/user/binaries/Makefile +++ b/tests/qemu-tests/tests/user/binaries/Makefile @@ -1,27 +1,36 @@ .PHONY: all -ARCHS = aarch64 arm riscv64 mips64 mips32 mipsel32 - -CC.aarch64 = aarch64-linux-gnu-gcc -CC.arm = arm-linux-gnueabihf-gcc -CC.riscv64 = riscv64-linux-gnu-gcc -# Ubuntu riscv64 cross compiler package doesn't have "--enable-multilib" enabled to allow compiling to 32-bit -# CC.riscv32 = riscv64-linux-gnu-gcc -CC.mips64 = mips64-linux-gnuabi64-gcc -CC.mips32 = mips-linux-gnu-gcc -CC.mipsel32 = mipsel-linux-gnu-gcc -# CC.loongarch64 = loongarch64-linux-gnu-gcc +ZIGPATH ?= ../../../../../.zig +ZIGCC = $(ZIGPATH)/zig cc + +ARCHS = aarch64 arm riscv64 mips32 mipsel32 mips64 loongarch64 s390x powerpc32 powerpc64 + +# In case we ever need a different compiler for an arch, fill it in here: +CC.aarch64 = ${ZIGCC} +CC.arm = ${ZIGCC} +# CC.riscv32 = ${ZIGCC} +CC.riscv64 = ${ZIGCC} +CC.mips32 = ${ZIGCC} +CC.mipsel32 = ${ZIGCC} +CC.mips64 = ${ZIGCC} +# CC.loongarch64 = ${ZIGCC} +# CC.s390x = ${ZIGCC} +CC.powerpc32 = ${ZIGCC} +CC.powerpc64 = ${ZIGCC} ALL_FLAGS = -g -CFLAGS.aarch64 = $(ALL_FLAGS) -CFLAGS.arm = $(ALL_FLAGS) -CFLAGS.riscv64 = -march=rv64gc -mabi=lp64d $(ALL_FLAGS) -# CFLAGS.riscv32 = -march=rv32gc $(ALL_FLAGS) -CFLAGS.mips64 = $(ALL_FLAGS) -CFLAGS.mips32 = $(ALL_FLAGS) # Big-endian MIPS -CFLAGS.mipsel32 = $(ALL_FLAGS) # Little-endian MIPS -# CFLAGS.loongarch64 = $(ALL_FLAGS) +CFLAGS.aarch64 = $(ALL_FLAGS) --target=aarch64-linux-musl +CFLAGS.arm = $(ALL_FLAGS) --target=arm-linux-musleabihf +# CFLAGS.riscv32 = $(ALL_FLAGS) --target=riscv32-linux-musl +CFLAGS.riscv64 = $(ALL_FLAGS) --target=riscv64-linux-musl +CFLAGS.mips32 = $(ALL_FLAGS) --target=mips-linux-musl # Big-endian MIPS +CFLAGS.mipsel32 = $(ALL_FLAGS) --target=mipsel-linux-musl # Little-endian MIPS +CFLAGS.mips64 = $(ALL_FLAGS) --target=mips64-linux-musl +# CFLAGS.loongarch64 = $(ALL_FLAGS) --target=loongarch64-linux-musl +# CFLAGS.s390x = $(ALL_FLAGS) --target=s390x-linux-musl -mcpu=z13 +CFLAGS.powerpc32 = $(ALL_FLAGS) --target=powerpc-linux-musl +CFLAGS.powerpc64 = $(ALL_FLAGS) --target=powerpc64-linux-musl AARCH64_SOURCES := $(wildcard *.aarch64.c) @@ -30,18 +39,37 @@ AARCH64_TARGETS := $(AARCH64_SOURCES:.aarch64.c=.aarch64.out) ARM_SOURCES := $(wildcard *.arm.c) ARM_TARGETS := $(ARM_SOURCES:.arm.c=.arm.out) +RISCV32_SOURCES := $(wildcard *.riscv32.c) +RISCV32_TARGETS := $(RISCV32_SOURCES:.riscv32.c=.riscv32.out) + RISCV64_SOURCES := $(wildcard *.riscv64.c) RISCV64_TARGETS := $(RISCV64_SOURCES:.riscv64.c=.riscv64.out) +MIPS32_SOURCES := $(wildcard *.mips32.c) +MIPS32_TARGETS := $(MIPS32_SOURCES:.mips32.c=.mips32.out) + +MIPSEL32_SOURCES := $(wildcard *.mipsel32.c) +MIPSEL32_TARGETS := $(MIPSEL32_SOURCES:.mipsel32.c=.mipsel32.out) + MIPS64_SOURCES := $(wildcard *.mips64.c) MIPS64_TARGETS := $(MIPS64_SOURCES:.mips64.c=.mips64.out) -MIPS32_SOURCES := $(wildcard *.mips32.c) -MIPS32_TARGETS := $(MIPS32_SOURCES:.mips32.c=.mips32.out) +LOONGARCH64_SOURCES := $(wildcard *.loongarch64.c) +LOONGARCH64_TARGETS := $(LOONGARCH64_SOURCES:.loongarch64.c=.loongarch64.out) + +S390X_SOURCES := $(wildcard *.s390x.c) +S390X_TARGETS := $(S390X_SOURCES:.s390x.c=.s390x.out) + +POWERPC32_SOURCES := $(wildcard *.powerpc32.c) +POWERPC32_TARGETS := $(POWERPC32_SOURCES:.powerpc32.c=.powerpc32.out) + +POWERPC64_SOURCES := $(wildcard *.powerpc64.c) +POWERPC64_TARGETS := $(POWERPC64_SOURCES:.powerpc64.c=.powerpc64.out) -# Build basic.c for all architectures -BASIC_C_TARGETS = $(ARCHS:%=basic.%.out) +ARCHES_TO_COMPILE_BASIC = aarch64 arm riscv64 mips32 mipsel32 mips64 +# Build basic.c for these architectures +BASIC_C_TARGETS = $(ARCHES_TO_COMPILE_BASIC:%=basic.%.out) basic.%.out: basic.c @echo "[+] Building '$@'" $(CC.$*) $(CFLAGS.$*) -o $@ $< @@ -56,7 +84,7 @@ basic.%.out: basic.c $(CC.riscv64) $(CFLAGS.riscv64) -o $@ $? -all: $(BASIC_C_TARGETS) $(AARCH64_TARGETS) $(ARM_TARGETS) $(RISCV64_TARGETS) $(MIPS64_TARGETS) $(MIPS32_TARGETS) +all: $(BASIC_C_TARGETS) $(AARCH64_TARGETS) $(ARM_TARGETS) $(RISCV32_TARGETS) $(RISCV64_TARGETS) $(MIPS32_TARGETS) $(MIPSEL32_TARGETS) $(MIPS64_TARGETS) $(LOONGARCH64_TARGETS) $(S390X_TARGETS) $(POWERPC32_TARGETS) $(POWERPC64_TARGETS) clean: - rm -f $(BASIC_C_TARGETS) $(AARCH64_TARGETS) $(ARM_TARGETS) $(RISCV64_TARGETS) $(MIPS64_TARGETS) $(MIPS32_TARGETS) + rm -f $(BASIC_C_TARGETS) $(AARCH64_TARGETS) $(ARM_TARGETS) $(RISCV32_TARGETS) $(RISCV64_TARGETS) $(MIPS32_TARGETS) $(MIPSEL32_TARGETS) $(MIPS64_TARGETS) $(LOONGARCH64_TARGETS) $(S390X_TARGETS) $(POWERPC32_TARGETS) $(POWERPC64_TARGETS) diff --git a/tests/qemu-tests/tests/user/test_aarch64.py b/tests/qemu-tests/tests/user/test_aarch64.py index ad8ef53a7..f89b04d5a 100644 --- a/tests/qemu-tests/tests/user/test_aarch64.py +++ b/tests/qemu-tests/tests/user/test_aarch64.py @@ -2,7 +2,7 @@ from __future__ import annotations import gdb import user -from capstone.arm64_const import ARM64_INS_BL +from capstone.aarch64_const import AARCH64_INS_BL import pwndbg.aglib.disasm.disassembly import pwndbg.aglib.nearpc @@ -11,13 +11,35 @@ import pwndbg.aglib.symbol import pwndbg.dbg from pwndbg.aglib.disasm.instruction import InstructionCondition +AARCH64_PREAMBLE = """ +.text +.globl _start +_start: +""" + +# The svc 0 is often the last instruction to be executed in these AArch64 tests and are placed in memory +# after all the other instructions. The bytes after it in memory (to fill the rest of the page) are typically filled with 0's. +# It was observed that compiling the program on different Linux distros even with the same Zig version might +# result in a couple of the bytes after svc being slightly different, resulting in the disassembly outputting +# slightly different instructions, like udf #0 or udf #23, depending on the source distro. +# To make this problem go away, the nops are added so that the disassembled instructions are consistent. AARCH64_GRACEFUL_EXIT = """ mov x0, 0 mov x8, 93 svc 0 +nop +nop +nop +nop +nop +nop +nop +nop +nop """ SIMPLE_FUNCTION = f""" +{AARCH64_PREAMBLE} bl my_function b end @@ -42,7 +64,7 @@ def test_aarch64_branch_enhancement(qemu_assembly_run): instruction = pwndbg.aglib.disasm.disassembly.one_with_config() - assert instruction.id == ARM64_INS_BL + assert instruction.id == AARCH64_INS_BL assert instruction.call_like assert not instruction.is_conditional_jump assert instruction.is_unconditional_jump @@ -54,23 +76,23 @@ def test_aarch64_branch_enhancement(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> bl my_function \n" + " ► 0x1010120 <_start> bl my_function \n" " x0: 0\n" " x1: 0\n" " x2: 0\n" " x3: 0\n" " \n" - " 0x10000004 <_start+4> b end \n" + " 0x1010124 <_start+4> b end \n" " ↓\n" - " 0x1000000c mov x0, #0 X0 => 0\n" - " 0x10000010 mov x8, #0x5d X8 => 0x5d\n" - " 0x10000014 svc #0\n" - " 0x10000018 udf #0\n" - " 0x1000001c udf #0\n" - " 0x10000020 udf #0\n" - " 0x10000024 udf #0\n" - " 0x10000028 udf #0\n" - " 0x1000002c udf #0\n" + " 0x101012c mov x0, #0 X0 => 0\n" + " 0x1010130 mov x8, #0x5d X8 => 0x5d\n" + " 0x1010134 svc #0\n" + " 0x1010138 nop \n" + " 0x101013c nop \n" + " 0x1010140 nop \n" + " 0x1010144 nop \n" + " 0x1010148 nop \n" + " 0x101014c nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -84,11 +106,17 @@ def test_aarch64_branch_enhancement(qemu_assembly_run): assert instruction.is_unconditional_jump +EXIT_SYSCALL = f""" +{AARCH64_PREAMBLE} +{AARCH64_GRACEFUL_EXIT} +""" + + def test_aarch64_syscall_annotation(qemu_assembly_run): """ Validate that we have enriched syscalls correctly. """ - qemu_assembly_run(AARCH64_GRACEFUL_EXIT, "aarch64") + qemu_assembly_run(EXIT_SYSCALL, "aarch64") instructions = pwndbg.aglib.disasm.disassembly.near( address=pwndbg.aglib.regs.pc, instructions=3, emulate=True @@ -105,17 +133,17 @@ def test_aarch64_syscall_annotation(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> mov x0, #0 X0 => 0\n" - " 0x10000004 <_start+4> mov x8, #0x5d X8 => 0x5d\n" - " 0x10000008 <_start+8> svc #0 \n" - " 0x1000000c udf #0\n" - " 0x10000010 udf #0\n" - " 0x10000014 udf #0\n" - " 0x10000018 udf #0\n" - " 0x1000001c udf #0\n" - " 0x10000020 udf #0\n" - " 0x10000024 udf #0\n" - " 0x10000028 udf #0\n" + " ► 0x1010120 <_start> mov x0, #0 X0 => 0\n" + " 0x1010124 <_start+4> mov x8, #0x5d X8 => 0x5d\n" + " 0x1010128 <_start+8> svc #0 \n" + " 0x101012c <_start+12> nop \n" + " 0x1010130 <_start+16> nop \n" + " 0x1010134 <_start+20> nop \n" + " 0x1010138 <_start+24> nop \n" + " 0x101013c <_start+28> nop \n" + " 0x1010140 <_start+32> nop \n" + " 0x1010144 <_start+36> nop \n" + " 0x1010148 <_start+40> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -135,6 +163,7 @@ def test_aarch64_syscall_annotation(qemu_assembly_run): CONDITIONAL_JUMPS = f""" +{AARCH64_PREAMBLE} mov x2, 0b1010 mov x3, 0 @@ -179,23 +208,23 @@ def test_aarch64_conditional_jump_output(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> mov x2, #0xa X2 => 0xa\n" - " 0x10000004 <_start+4> mov x3, #0 X3 => 0\n" - " 0x10000008 <_start+8> ✔ cbz x3, A \n" + " ► 0x1010120 <_start> mov x2, #0xa X2 => 0xa\n" + " 0x1010124 <_start+4> mov x3, #0 X3 => 0\n" + " 0x1010128 <_start+8> ✔ cbz x3, A \n" " ↓\n" - " 0x10000010 ✔ cbnz x2, B \n" + " 0x1010130 ✔ cbnz x2, B \n" " ↓\n" - " 0x10000018 ✔ tbz w2, #0, C \n" + " 0x1010138 ✔ tbz w2, #0, C \n" " ↓\n" - " 0x10000020 ✔ tbnz w2, #3, D \n" + " 0x1010140 ✔ tbnz w2, #3, D \n" " ↓\n" - " 0x10000028 cmp x2, x3 0xa - 0x0 CPSR => 0x20000000 [ n z C v q pan il d a i f el:0 sp ]\n" - " 0x1000002c b.eq E \n" + " 0x1010148 cmp x2, x3 0xa - 0x0 CPSR => 0x20000000 [ n z C v q pan il d a i f el:0 sp ]\n" + " 0x101014c b.eq E \n" " \n" - " 0x10000030 nop \n" - " 0x10000034 ✔ b.ne F \n" + " 0x1010150 nop \n" + " 0x1010154 ✔ b.ne F \n" " ↓\n" - " 0x1000003c mov x0, #0 X0 => 0\n" + " 0x101015c mov x0, #0 X0 => 0\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -249,7 +278,8 @@ def test_conditional_jumps_no_emulate(qemu_assembly_run): test_aarch64_conditional_jumps(qemu_assembly_run) -AARCH64_BINARY_OPERATIONS = """ +AARCH64_BINARY_OPERATIONS = f""" +{AARCH64_PREAMBLE} mov x0, 7 mov x1, 563 add x2, x0, x1 @@ -273,17 +303,17 @@ def test_aarch64_binary_operations(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> mov x0, #7 X0 => 7\n" - " 0x10000004 <_start+4> mov x1, #0x233 X1 => 0x233\n" - " 0x10000008 <_start+8> add x2, x0, x1 X2 => 0x23a (0x7 + 0x233)\n" - " 0x1000000c <_start+12> sub x3, x1, x0 X3 => 0x22c (0x233 - 0x7)\n" - " 0x10000010 <_start+16> adds x2, x0, x1 X2 => 0x23a (0x7 + 0x233)\n" - " 0x10000014 <_start+20> subs x3, x1, x0 X3 => 0x22c (0x233 - 0x7)\n" - " 0x10000018 <_start+24> and x4, x0, x1 X4 => 3 (0x7 & 0x233)\n" - " 0x1000001c <_start+28> orr x5, x0, x1 X5 => 0x237 (0x7 | 0x233)\n" - " 0x10000020 <_start+32> eor x6, x0, x1 X6 => 0x234 (0x7 ^ 0x233)\n" - " 0x10000024 <_start+36> mul x10, x0, x1 X10 => 0xf65 (0x7 * 0x233)\n" - " 0x10000028 <_start+40> udiv x11, x1, x0 X11 => 80 (0x233 / 0x7)\n" + " ► 0x1010120 <_start> mov x0, #7 X0 => 7\n" + " 0x1010124 <_start+4> mov x1, #0x233 X1 => 0x233\n" + " 0x1010128 <_start+8> add x2, x0, x1 X2 => 0x23a (0x7 + 0x233)\n" + " 0x101012c <_start+12> sub x3, x1, x0 X3 => 0x22c (0x233 - 0x7)\n" + " 0x1010130 <_start+16> adds x2, x0, x1 X2 => 0x23a (0x7 + 0x233)\n" + " 0x1010134 <_start+20> subs x3, x1, x0 X3 => 0x22c (0x233 - 0x7)\n" + " 0x1010138 <_start+24> and x4, x0, x1 X4 => 3 (0x7 & 0x233)\n" + " 0x101013c <_start+28> orr x5, x0, x1 X5 => 0x237 (0x7 | 0x233)\n" + " 0x1010140 <_start+32> eor x6, x0, x1 X6 => 0x234 (0x7 ^ 0x233)\n" + " 0x1010144 <_start+36> mul x10, x0, x1 X10 => 0xf65 (0x7 * 0x233)\n" + " 0x1010148 <_start+40> udiv x11, x1, x0 X11 => 80 (0x233 / 0x7)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -291,7 +321,8 @@ def test_aarch64_binary_operations(qemu_assembly_run): # Nops are so that when we break at `stores`, the display doesn't have any previous instructions -AARCH64_STORES = """ +AARCH64_STORES = f""" +{AARCH64_PREAMBLE} ldr x0, =0x123456789ABCDEF0 @@ -343,24 +374,26 @@ def test_aarch64_store_instructions(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000028 ldr x4, stores+56 X4, [stores+56] => 0x4010e8 (value1) ◂— 0\n" - " 0x1000002c strb w0, [x4] [value1] <= 0xf0\n" - " 0x10000030 ldr x5, stores+64 X5, [stores+64] => 0x4010e9 (value2) ◂— 0\n" - " 0x10000034 strh w0, [x5] [value2] <= 0xdef0\n" - " 0x10000038 ldr x6, stores+72 X6, [stores+72] => 0x4010eb (value4) ◂— 0\n" - " 0x1000003c str w0, [x6] [value4] <= 0x9abcdef0\n" - " 0x10000040 ldr x7, stores+80 X7, [stores+80] => 0x4010ef (value8) ◂— 0\n" - " 0x10000044 str x0, [x7] [value8] <= 0x123456789abcdef0\n" - " 0x10000048 mov x8, #0x5d X8 => 0x5d\n" - " 0x1000004c mov x0, #0 X0 => 0\n" - " 0x10000050 svc #0 \n" + " ► 0x1010180 ldr x4, stores+56 X4, [stores+56] => 0x10201d8 (value1) ◂— 0\n" + " 0x1010184 strb w0, [x4] [value1] <= 0xf0\n" + " 0x1010188 ldr x5, stores+64 X5, [stores+64] => 0x10201d9 (value2) ◂— 0\n" + " 0x101018c strh w0, [x5] [value2] <= 0xdef0\n" + " 0x1010190 ldr x6, stores+72 X6, [stores+72] => 0x10201db (value4) ◂— 0\n" + " 0x1010194 str w0, [x6] [value4] <= 0x9abcdef0\n" + " 0x1010198 ldr x7, stores+80 X7, [stores+80] => 0x10201df (value8) ◂— 0\n" + " 0x101019c str x0, [x7] [value8] <= 0x123456789abcdef0\n" + " 0x10101a0 mov x8, #0x5d X8 => 0x5d\n" + " 0x10101a4 mov x0, #0 X0 => 0\n" + " 0x10101a8 svc #0 \n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -AARCH64_LOADS = """ +AARCH64_LOADS = f""" +{AARCH64_PREAMBLE} + ldr x0, =0x123456789ABCDEF0 stores: @@ -416,17 +449,17 @@ def test_aarch64_load_instructions(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000024 ldrb w9, [x4] W9, [value1] => 0xf0\n" - " 0x10000028 ldrsb w10, [x4] W10, [value1] => 0xfffffff0\n" - " 0x1000002c ldrh w12, [x5] W12, [value2] => 0xdef0\n" - " 0x10000030 ldrsh w13, [x5] W13, [value2] => 0xffffdef0\n" - " 0x10000034 ldr w15, [x6] W15, [value4] => 0x9abcdef0\n" - " 0x10000038 ldrsw x16, [x6] X16, [value4] => 0xffffffff9abcdef0\n" - " 0x1000003c ldr x18, [x6] X18, [value4] => 0x9abcdef09abcdef0\n" - " 0x10000040 mov x8, #0x5d X8 => 0x5d\n" - " 0x10000044 mov x0, #0 X0 => 0\n" - " 0x10000048 svc #0 \n" - " 0x1000004c udf #0\n" + " ► 0x101017c ldrb w9, [x4] W9, [value1] => 0xf0\n" + " 0x1010180 ldrsb w10, [x4] W10, [value1] => 0xfffffff0\n" + " 0x1010184 ldrh w12, [x5] W12, [value2] => 0xdef0\n" + " 0x1010188 ldrsh w13, [x5] W13, [value2] => 0xffffdef0\n" + " 0x101018c ldr w15, [x6] W15, [value4] => 0x9abcdef0\n" + " 0x1010190 ldrsw x16, [x6] X16, [value4] => 0xffffffff9abcdef0\n" + " 0x1010194 ldr x18, [x6] X18, [value4] => 0x9abcdef09abcdef0\n" + " 0x1010198 mov x8, #0x5d X8 => 0x5d\n" + " 0x101019c mov x0, #0 X0 => 0\n" + " 0x10101a0 svc #0 \n" + " 0x10101a4 udf #0\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -434,6 +467,8 @@ def test_aarch64_load_instructions(qemu_assembly_run): CPSR_REGISTER_TEST = f""" +{AARCH64_PREAMBLE} + mov x19, #8 cmn x19, #8 b.ne exit @@ -474,18 +509,18 @@ def test_aarch64_write_cpsr_when_zero(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " 0x10000000 <_start> mov x19, #8 X19 => 8\n" - " 0x10000004 <_start+4> cmn x19, #8 8 + 8 CPSR => 0x0 [ n z c v q pan il d a i f el:0 sp ]\n" - " ► 0x10000008 <_start+8> ✔ b.ne exit \n" + " 0x1010120 <_start> mov x19, #8 X19 => 8\n" + " 0x1010124 <_start+4> cmn x19, #8 8 + 8 CPSR => 0x0 [ n z c v q pan il d a i f el:0 sp ]\n" + " ► 0x1010128 <_start+8> ✔ b.ne exit \n" " ↓\n" - " 0x10000020 mov x0, #0 X0 => 0\n" - " 0x10000024 mov x8, #0x5d X8 => 0x5d\n" - " 0x10000028 svc #0 \n" - " 0x1000002c udf #0\n" - " 0x10000030 udf #0\n" - " 0x10000034 udf #0\n" - " 0x10000038 udf #0\n" - " 0x1000003c udf #0\n" + " 0x1010140 mov x0, #0 X0 => 0\n" + " 0x1010144 mov x8, #0x5d X8 => 0x5d\n" + " 0x1010148 svc #0 \n" + " 0x101014c nop \n" + " 0x1010150 nop \n" + " 0x1010154 nop \n" + " 0x1010158 nop \n" + " 0x101015c nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -493,6 +528,8 @@ def test_aarch64_write_cpsr_when_zero(qemu_assembly_run): AARCH64_MEMORY_OPERAND_TEST = rf""" +{AARCH64_PREAMBLE} + LDR X1, =msg LDR W0, [X1], #4 LDR W0, [X1, #4] @@ -530,24 +567,26 @@ def test_aarch64_memory_operands(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> ldr x1, data+4 X1, [data+4] => 0x4010e8 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" - " 0x10000004 <_start+4> ldr w0, [x1], #4 W0, [msg] => 0x44434241\n" - " 0x10000008 <_start+8> ldr w0, [x1, #4] W0, [msg+8] => 0x4c4b4a49\n" - " 0x1000000c <_start+12> mov x3, #8 X3 => 8\n" - " 0x10000010 <_start+16> ldr w4, [x1, x3] W4, [msg+12] => 0x504f4e4d\n" - " 0x10000014 <_start+20> ldur w5, [x1, #-4] W5, [msg] => 0x44434241\n" - " 0x10000018 <_start+24> mov x6, #-4 X6 => 0xfffffffffffffffc\n" - " 0x1000001c <_start+28> ldr w7, [x1, x6] W7, [msg] => 0x44434241\n" - " 0x10000020 mov x0, #0 X0 => 0\n" - " 0x10000024 mov x8, #0x5d X8 => 0x5d\n" - " 0x10000028 svc #0 \n" + " ► 0x1010158 <_start> ldr x1, data X1, [data] => 0x10201b0 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" + " 0x101015c <_start+4> ldr w0, [x1], #4 W0, [msg] => 0x44434241\n" + " 0x1010160 <_start+8> ldr w0, [x1, #4] W0, [msg+8] => 0x4c4b4a49\n" + " 0x1010164 <_start+12> mov x3, #8 X3 => 8\n" + " 0x1010168 <_start+16> ldr w4, [x1, x3] W4, [msg+12] => 0x504f4e4d\n" + " 0x101016c <_start+20> ldur w5, [x1, #-4] W5, [msg] => 0x44434241\n" + " 0x1010170 <_start+24> mov x6, #-4 X6 => 0xfffffffffffffffc\n" + " 0x1010174 <_start+28> ldr w7, [x1, x6] W7, [msg] => 0x44434241\n" + " 0x1010178 mov x0, #0 X0 => 0\n" + " 0x101017c mov x8, #0x5d X8 => 0x5d\n" + " 0x1010180 svc #0 \n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -AARCH64_SHIFTS_AND_EXTENDS = r""" +AARCH64_SHIFTS_AND_EXTENDS = f""" +{AARCH64_PREAMBLE} + mov X1, 1 mov X3, 8 ADD X0, X1, X1, LSL 2 @@ -558,7 +597,7 @@ ADD X0, X1, W2, SXTB ADD X0, X1, W2, UXTB ADD X0, X1, X2, ASR 2 -MOV X0, X1, ROR 2 +ORR X0, xzr, X1, ror #2 SXTB X2, w2 ADD X0, X1, X2, ASR 2 @@ -577,24 +616,25 @@ def test_aarch64_shifts_and_extends(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> mov x1, #1 X1 => 1\n" - " 0x10000004 <_start+4> mov x3, #8 X3 => 8\n" - " 0x10000008 <_start+8> add x0, x1, x1, lsl #2 X0 => 5 (1 + 4)\n" - " 0x1000000c <_start+12> add x0, x1, x3, lsr #2 X0 => 3 (1 + 2)\n" - " 0x10000010 <_start+16> mov w2, #-1 W2 => 0xffffffff\n" - " 0x10000014 <_start+20> add x0, x1, w2, sxtb X0 => 0 (0x1 + 0xffffffffffffffff)\n" - " 0x10000018 <_start+24> add x0, x1, w2, uxtb X0 => 0x100 (0x1 + 0xff)\n" - " 0x1000001c <_start+28> add x0, x1, x2, asr #2 X0 => 0x40000000 (0x1 + 0x3fffffff)\n" - " 0x10000020 <_start+32> orr x0, xzr, x1, ror #2 X0 => 0x4000000000000000 (0x0 | 0x4000000000000000)\n" - " 0x10000024 <_start+36> sxtb x2, w2\n" - " 0x10000028 <_start+40> add x0, x1, x2, asr #2 X0 => 0 (0x1 + 0xffffffffffffffff)\n" + " ► 0x1010120 <_start> mov x1, #1 X1 => 1\n" + " 0x1010124 <_start+4> mov x3, #8 X3 => 8\n" + " 0x1010128 <_start+8> add x0, x1, x1, lsl #2 X0 => 5 (1 + 4)\n" + " 0x101012c <_start+12> add x0, x1, x3, lsr #2 X0 => 3 (1 + 2)\n" + " 0x1010130 <_start+16> mov w2, #-1 W2 => 0xffffffff\n" + " 0x1010134 <_start+20> add x0, x1, w2, sxtb X0 => 0 (0x1 + 0xffffffffffffffff)\n" + " 0x1010138 <_start+24> add x0, x1, w2, uxtb X0 => 0x100 (0x1 + 0xff)\n" + " 0x101013c <_start+28> add x0, x1, x2, asr #2 X0 => 0x40000000 (0x1 + 0x3fffffff)\n" + " 0x1010140 <_start+32> orr x0, xzr, x1, ror #2 X0 => 0x4000000000000000 (0x0 | 0x4000000000000000)\n" + " 0x1010144 <_start+36> sxtb x2, w2\n" + " 0x1010148 <_start+40> add x0, x1, x2, asr #2 X0 => 0 (0x1 + 0xffffffffffffffff)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -AARCH64_MEMORY_OPERAND_SHIFT = r""" +AARCH64_MEMORY_OPERAND_SHIFT = rf""" +{AARCH64_PREAMBLE} LDR x2, =msg ADD x2,x2,16 MOV w3, 0xffffffff @@ -616,12 +656,12 @@ def test_aarch64_shifts_and_extends_in_memory_operands(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> ldr x2, _start+24 X2, [_start+24] => 0x4010e8 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" - " 0x10000004 <_start+4> add x2, x2, #0x10 X2 => 0x4010f8 (msg+16) (0x4010e8 + 0x10)\n" - " 0x10000008 <_start+8> mov w3, #-1 W3 => 0xffffffff\n" - " 0x1000000c <_start+12> ldr x1, [x2, w3, sxtw] X1, [msg+15] => 0x5756555453525150 ('PQRSTUVW')\n" - " 0x10000010 <_start+16> ldr x1, [x2, w3, sxtw #3] X1, [msg+8] => 0x504f4e4d4c4b4a49 ('IJKLMNOP')\n" - " 0x10000014 <_start+20> nop \n" + " ► 0x1010158 <_start> ldr x2, _start+24 X2, [_start+24] => 0x1020178 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" + " 0x101015c <_start+4> add x2, x2, #0x10 X2 => 0x1020188 (msg+16) (0x1020178 + 0x10)\n" + " 0x1010160 <_start+8> mov w3, #-1 W3 => 0xffffffff\n" + " 0x1010164 <_start+12> ldr x1, [x2, w3, sxtw] X1, [msg+15] => 0x5756555453525150 ('PQRSTUVW')\n" + " 0x1010168 <_start+16> ldr x1, [x2, w3, sxtw #3] X1, [msg+8] => 0x504f4e4d4c4b4a49 ('IJKLMNOP')\n" + " 0x101016c <_start+20> nop \n" "\n" "\n" "\n" @@ -633,7 +673,9 @@ def test_aarch64_shifts_and_extends_in_memory_operands(qemu_assembly_run): assert dis == expected -AARCH64_SHIFT_INSTRUCTIONS = """ +AARCH64_SHIFT_INSTRUCTIONS = f""" +{AARCH64_PREAMBLE} + MOV x0, #3 MOV x1, #0xF000 MOV x2, #0x1234 @@ -662,17 +704,17 @@ def test_aarch64_shift_instructions(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────────[ DISASM / aarch64 / set emulate on ]──────────────────────\n" - " ► 0x10000000 <_start> mov x0, #3 X0 => 3\n" - " 0x10000004 <_start+4> mov x1, #0xf000 X1 => 0xf000\n" - " 0x10000008 <_start+8> mov x2, #0x1234 X2 => 0x1234\n" - " 0x1000000c <_start+12> lsr x3, x1, #4 X3 => 0xf00 (0xf000 >> 0x4)\n" - " 0x10000010 <_start+16> lsr x4, x1, x0 X4 => 0x1e00\n" - " 0x10000014 <_start+20> lsl x5, x4, #4 X5 => 0x1e000 (0x1e00 << 0x4)\n" - " 0x10000018 <_start+24> lsl x6, x4, x2 X6 => 0xe000000000000000\n" - " 0x1000001c <_start+28> asr x6, x4, #4 X6 => 0x1e0 (0x1e00 >>s 0x4)\n" - " 0x10000020 <_start+32> asr x6, x4, x0 X6 => 0x3c0\n" - " 0x10000024 <_start+36> ror x6, x4, #4 X6 => 0x1e0 (0x1e00 >>r 0x4)\n" - " 0x10000028 <_start+40> ror x6, x4, x0 X6 => 0x3c0\n" + " ► 0x1010120 <_start> mov x0, #3 X0 => 3\n" + " 0x1010124 <_start+4> mov x1, #0xf000 X1 => 0xf000\n" + " 0x1010128 <_start+8> mov x2, #0x1234 X2 => 0x1234\n" + " 0x101012c <_start+12> lsr x3, x1, #4 X3 => 0xf00 (0xf000 >> 0x4)\n" + " 0x1010130 <_start+16> lsr x4, x1, x0 X4 => 0x1e00\n" + " 0x1010134 <_start+20> lsl x5, x4, #4 X5 => 0x1e000 (0x1e00 << 0x4)\n" + " 0x1010138 <_start+24> lsl x6, x4, x2 X6 => 0xe000000000000000\n" + " 0x101013c <_start+28> asr x6, x4, #4 X6 => 0x1e0 (0x1e00 >>s 0x4)\n" + " 0x1010140 <_start+32> asr x6, x4, x0 X6 => 0x3c0\n" + " 0x1010144 <_start+36> ror x6, x4, #4 X6 => 0x1e0 (0x1e00 >>r 0x4)\n" + " 0x1010148 <_start+40> ror x6, x4, x0 X6 => 0x3c0\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -693,7 +735,7 @@ def test_aarch64_reference(qemu_start_binary): gdb.execute("auxv", to_string=True) assert ( gdb.execute("cpsr", to_string=True, from_tty=False).strip() - == "cpsr 0x60000000 [ n Z C v q pan il d a i f el:0 sp ]" + == "cpsr 0x0 [ n z c v q pan il d a i f el:0 sp ]" ) gdb.execute("context", to_string=True) gdb.execute("hexdump", to_string=True) diff --git a/tests/qemu-tests/tests/user/test_arm.py b/tests/qemu-tests/tests/user/test_arm.py index a13a0b252..93e576599 100644 --- a/tests/qemu-tests/tests/user/test_arm.py +++ b/tests/qemu-tests/tests/user/test_arm.py @@ -4,6 +4,12 @@ import gdb import pwndbg.color +ARM_PREAMBLE = """ +.text +.globl _start +_start: +""" + ARM_GRACEFUL_EXIT = """ mov r0, 0 mov r7, 0xf8 @@ -11,6 +17,7 @@ swi #0 """ ARM_BRANCHES = f""" +{ARM_PREAMBLE} mov r2, #5 mov r1, #10 cmp r0, r1 @@ -45,22 +52,23 @@ def test_arm_simple_branch(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> mov r2, #5 R2 => 5\n" - " 0x10000004 <_start+4> mov r1, #0xa R1 => 0xa\n" - " 0x10000008 <_start+8> cmp r0, r1 0x0 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" - " 0x1000000c <_start+12> ✔ bne not_equal \n" + " ► 0x200b4 <_start> mov r2, #5 R2 => 5\n" + " 0x200b8 <_start+4> mov r1, #0xa R1 => 0xa\n" + " 0x200bc <_start+8> cmp r0, r1 0x0 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" + " 0x200c0 <_start+12> ✔ bne not_equal \n" " ↓\n" - " 0x10000018 mov r3, #1 R3 => 1\n" - " 0x1000001c cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n" - " 0x10000020 ✔ bgt greater \n" + " 0x200cc mov r3, #1 R3 => 1\n" + " 0x200d0 cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n" + " 0x200d4 ✔ bgt greater \n" " ↓\n" - " 0x1000002c cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" - " 0x10000030 ✔ bls end \n" + " 0x200e0 cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" + " 0x200e4 ✔ bls end \n" " ↓\n" - " 0x1000003c mov r0, #0 R0 => 0\n" - " 0x10000040 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200f0 mov r0, #0 R0 => 0\n" + " 0x200f4 mov r7, #0xf8 R7 => 0xf8\n" "────────────────────────────────────────────────────────────────────────────────\n" ) + assert dis == expected gdb.execute("si 8") @@ -71,19 +79,19 @@ def test_arm_simple_branch(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " 0x1000000c <_start+12> ✔ bne not_equal \n" + " 0x200c0 <_start+12> ✔ bne not_equal \n" " ↓\n" - " 0x10000018 mov r3, #1 R3 => 1\n" - " 0x1000001c cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n" - " 0x10000020 ✔ bgt greater \n" + " 0x200cc mov r3, #1 R3 => 1\n" + " 0x200d0 cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n" + " 0x200d4 ✔ bgt greater \n" " ↓\n" - " 0x1000002c cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" - " ► 0x10000030 ✔ bls end \n" + " 0x200e0 cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n" + " ► 0x200e4 ✔ bls end \n" " ↓\n" - " 0x1000003c mov r0, #0 R0 => 0\n" - " 0x10000040 mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000044 svc #0 \n" - " 0x10000048 andeq r1, r0, r1, asr #24\n" + " 0x200f0 mov r0, #0 R0 => 0\n" + " 0x200f4 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200f8 svc #0 \n" + " 0x200fc andeq r3, r0, r1, asr #32\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -91,6 +99,7 @@ def test_arm_simple_branch(qemu_assembly_run): ARM_INTERWORKING_BRANCH = f""" +{ARM_PREAMBLE} add r0, pc, #1 bx r0 @@ -120,14 +129,14 @@ def test_arm_interworking_branch(qemu_assembly_run): dis = gdb.execute("emulate 3", to_string=True) expected = ( - " ► 0x10000000 <_start> add r0, pc, #1 R0 => 0x10000009 (_start+9) (0x10000008 + 0x1)\n" - " 0x10000004 <_start+4> bx r0 <_start+8>\n" + " ► 0x200b4 <_start> add r0, pc, #1 R0 => 0x200bd (_start+9) (0x200bc + 0x1)\n" + " 0x200b8 <_start+4> bx r0 <_start+8>\n" " ↓\n" - " 0x10000008 <_start+8> mov.w r2, #4 R2 => 4\n" - " 0x1000000c <_start+12> add r2, r0 R2 => 0x1000000d (_start+13) (0x4 + 0x10000009)\n" - " 0x1000000e mov.w r0, #0 R0 => 0\n" - " 0x10000012 mov.w r7, #0xf8 R7 => 0xf8\n" - " 0x10000016 svc #0 \n" + " 0x200bc <_start+8> mov.w r2, #4 R2 => 4\n" + " 0x200c0 <_start+12> add r2, r0 R2 => 0x200c1 (_start+13) (0x4 + 0x200bd)\n" + " 0x200c2 mov.w r0, #0 R0 => 0\n" + " 0x200c6 mov.w r7, #0xf8 R7 => 0xf8\n" + " 0x200ca svc #0 \n" ) assert dis == expected @@ -139,20 +148,21 @@ def test_arm_interworking_branch(qemu_assembly_run): dis = gdb.execute("emulate 3", to_string=True) expected = ( - " 0x10000000 <_start> add r0, pc, #1 R0 => 0x10000009 (_start+9) (0x10000008 + 0x1)\n" - " 0x10000004 <_start+4> bx r0 <_start+8>\n" + " 0x200b4 <_start> add r0, pc, #1 R0 => 0x200bd (_start+9) (0x200bc + 0x1)\n" + " 0x200b8 <_start+4> bx r0 <_start+8>\n" " ↓\n" - " ► 0x10000008 <_start+8> mov.w r2, #4 R2 => 4\n" - " 0x1000000c <_start+12> add r2, r0 R2 => 0x1000000d (_start+13) (0x4 + 0x10000009)\n" - " 0x1000000e mov.w r0, #0 R0 => 0\n" - " 0x10000012 mov.w r7, #0xf8 R7 => 0xf8\n" - " 0x10000016 svc #0 \n" + " ► 0x200bc <_start+8> mov.w r2, #4 R2 => 4\n" + " 0x200c0 <_start+12> add r2, r0 R2 => 0x200c1 (_start+13) (0x4 + 0x200bd)\n" + " 0x200c2 mov.w r0, #0 R0 => 0\n" + " 0x200c6 mov.w r7, #0xf8 R7 => 0xf8\n" + " 0x200ca svc #0 \n" ) assert dis == expected -ARM_IMPLICIT_BRANCH = """ +ARM_IMPLICIT_BRANCH = f""" +{ARM_PREAMBLE} ldr R1, =_target ADD PC, R1, #1 @@ -189,25 +199,26 @@ def test_arm_implicit_branch(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr r1, [pc, #0x28] R1, [_target+36] => 0x1000000c (_target) ◂— 0x102f04f\n" - " 0x10000004 <_start+4> add pc, r1, #1 <_target>\n" + " ► 0x200b4 <_start> ldr r1, [pc, #0x28] R1, [_target+36] => 0x200c0 (_target) ◂— 0x102f04f\n" + " 0x200b8 <_start+4> add pc, r1, #1 <_target>\n" " ↓\n" - " 0x1000000c <_target> mov.w r1, #2 R1 => 2\n" - " 0x10000010 <_target+4> mov.w r2, #4 R2 => 4\n" - " 0x10000014 <_target+8> mov.w r6, #3 R6 => 3\n" - " 0x10000018 <_target+12> add.w r1, r2, r3 R1 => 4 (4 + 0)\n" - " 0x1000001c <_target+16> sub.w r4, r5, r6 R4 => 0xfffffffd (0 - 3)\n" - " 0x10000020 <_target+20> orr.w r6, r6, r5 R6 => 3 (3 | 0)\n" - " 0x10000024 <_target+24> and.w r2, r2, r5 R2 => 0 (4 & 0)\n" - " 0x10000028 <_target+28> eor.w r1, r2, r1 R1 => 4 (0 ^ 4)\n" - " 0x1000002c <_target+32> lsr.w r3, r3, #4 R3 => 0 (0 >> 4)\n" + " 0x200c0 <_target> mov.w r1, #2 R1 => 2\n" + " 0x200c4 <_target+4> mov.w r2, #4 R2 => 4\n" + " 0x200c8 <_target+8> mov.w r6, #3 R6 => 3\n" + " 0x200cc <_target+12> add.w r1, r2, r3 R1 => 4 (4 + 0)\n" + " 0x200d0 <_target+16> sub.w r4, r5, r6 R4 => 0xfffffffd (0 - 3)\n" + " 0x200d4 <_target+20> orr.w r6, r6, r5 R6 => 3 (3 | 0)\n" + " 0x200d8 <_target+24> and.w r2, r2, r5 R2 => 0 (4 & 0)\n" + " 0x200dc <_target+28> eor.w r1, r2, r1 R1 => 4 (0 ^ 4)\n" + " 0x200e0 <_target+32> lsr.w r3, r3, #4 R3 => 0 (0 >> 4)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -ARM_IMPLICIT_BRANCH_NEXT_INSTRUCTION = """ +ARM_IMPLICIT_BRANCH_NEXT_INSTRUCTION = f""" +{ARM_PREAMBLE} ldr R1, =_target ADD PC, R1, #1 @@ -241,18 +252,18 @@ def test_arm_implicit_branch_next_instruction(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr r1, [pc, #0x24] R1, [_target+36] => 0x10000008 (_target) ◂— 0x103eb02\n" - " 0x10000004 <_start+4> add pc, r1, #1 <_target>\n" + " ► 0x200b4 <_start> ldr r1, [pc, #0x24] R1, [_target+36] => 0x200bc (_target) ◂— 0x103eb02\n" + " 0x200b8 <_start+4> add pc, r1, #1 <_target>\n" " ↓\n" - " 0x10000008 <_target> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x1000000c <_target+4> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000010 <_target+8> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000014 <_target+12> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000018 <_target+16> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x1000001c <_target+20> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000020 <_target+24> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000024 <_target+28> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" - " 0x10000028 <_target+32> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200bc <_target> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200c0 <_target+4> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200c4 <_target+8> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200c8 <_target+12> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200cc <_target+16> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200d0 <_target+20> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200d4 <_target+24> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200d8 <_target+28> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" + " 0x200dc <_target+32> add.w r1, r2, r3 R1 => 0 (0 + 0)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -260,6 +271,7 @@ def test_arm_implicit_branch_next_instruction(qemu_assembly_run): ARM_LDR_TO_PC = f""" +{ARM_PREAMBLE} ldr pc, =end nop @@ -283,13 +295,13 @@ def test_arm_implicit_branch_ldr(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr pc, [pc, #0xc] \n" + " ► 0x200b4 <_start> ldr pc, [pc, #0xc] \n" " ↓\n" - " 0x10000008 mov r0, #0 R0 => 0\n" - " 0x1000000c mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000010 svc #0 \n" - " 0x10000014 andne r0, r0, r8\n" - " 0x10000018 andeq r1, r0, r1, asr #24\n" + " 0x200bc mov r0, #0 R0 => 0\n" + " 0x200c0 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200c4 svc #0 \n" + " 0x200c8 strheq r0, [r2], -r12\n" + " 0x200cc andeq r3, r0, r1, asr #32\n" "\n" "\n" "\n" @@ -307,13 +319,13 @@ def test_arm_implicit_branch_ldr(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " 0x10000000 <_start> ldr pc, [pc, #0xc] \n" + " 0x200b4 <_start> ldr pc, [pc, #0xc] \n" " ↓\n" - " ► 0x10000008 mov r0, #0 R0 => 0\n" - " 0x1000000c mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000010 svc #0 \n" - " 0x10000014 andne r0, r0, r8\n" - " 0x10000018 andeq r1, r0, r1, asr #24\n" + " ► 0x200bc mov r0, #0 R0 => 0\n" + " 0x200c0 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200c4 svc #0 \n" + " 0x200c8 strheq r0, [r2], -r12\n" + " 0x200cc andeq r3, r0, r1, asr #32\n" "\n" "\n" "\n" @@ -346,6 +358,7 @@ def test_arm_mode_banner(qemu_assembly_run): ARM_STACK_CRASH = f""" +{ARM_PREAMBLE} mov r0, #4 mov r1, #3 add r2, r0, r1 @@ -379,17 +392,17 @@ def test_arm_stack_pointer_check(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> mov r0, #4 R0 => 4\n" - " 0x10000004 <_start+4> mov r1, #3 R1 => 3\n" - " 0x10000008 <_start+8> add r2, r0, r1 R2 => 7 (4 + 3)\n" - " 0x1000000c <_start+12> sub r3, r2, #2 R3 => 5 (7 - 2)\n" - f" 0x10000010 <_start+16> str r3, [sp, #-4]! [{hex(pwndbg.aglib.regs.sp - 4)}] <= 5\n" - " 0x10000014 <_start+20> pop {r4}\n" - " 0x10000018 <_start+24> mul r4, r2, r1 R4 => 21 (7 * 3)\n" - " 0x1000001c <_start+28> add r4, r4, #1 R4 => 22 (0x15 + 0x1)\n" - " 0x10000020 mov r0, #0 R0 => 0\n" - " 0x10000024 mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000028 svc #0 \n" + " ► 0x200b4 <_start> mov r0, #4 R0 => 4\n" + " 0x200b8 <_start+4> mov r1, #3 R1 => 3\n" + " 0x200bc <_start+8> add r2, r0, r1 R2 => 7 (4 + 3)\n" + " 0x200c0 <_start+12> sub r3, r2, #2 R3 => 5 (7 - 2)\n" + f" 0x200c4 <_start+16> str r3, [sp, #-4]! [{hex(pwndbg.aglib.regs.sp - 4)}] <= 5\n" + " 0x200c8 <_start+20> pop {r4}\n" + " 0x200cc <_start+24> mul r4, r2, r1 R4 => 21 (7 * 3)\n" + " 0x200d0 <_start+28> add r4, r4, #1 R4 => 22 (0x15 + 0x1)\n" + " 0x200d4 mov r0, #0 R0 => 0\n" + " 0x200d8 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200dc svc #0 \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -397,6 +410,7 @@ def test_arm_stack_pointer_check(qemu_assembly_run): ARM_CMP = f""" +{ARM_PREAMBLE} mov r0, #5 mov r1, #5 cmp r0, r1 @@ -416,15 +430,15 @@ def test_arm_cmp_instructions(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> mov r0, #5 R0 => 5\n" - " 0x10000004 <_start+4> mov r1, #5 R1 => 5\n" - " 0x10000008 <_start+8> cmp r0, r1 5 - 5 CPSR => 0x60000010 [ n Z C v q j t e a i f ]\n" - " 0x1000000c <_start+12> ✔ beq end \n" + " ► 0x200b4 <_start> mov r0, #5 R0 => 5\n" + " 0x200b8 <_start+4> mov r1, #5 R1 => 5\n" + " 0x200bc <_start+8> cmp r0, r1 5 - 5 CPSR => 0x60000010 [ n Z C v q j t e a i f ]\n" + " 0x200c0 <_start+12> ✔ beq end \n" " ↓\n" - " 0x1000001c mov r0, #0 R0 => 0\n" - " 0x10000020 mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000024 svc #0 \n" - " 0x10000028 andeq r1, r0, r1, asr #24\n" + " 0x200d0 mov r0, #0 R0 => 0\n" + " 0x200d4 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200d8 svc #0 \n" + " 0x200dc andeq r3, r0, r1, asr #32\n" "\n" "\n" "────────────────────────────────────────────────────────────────────────────────\n" @@ -434,6 +448,7 @@ def test_arm_cmp_instructions(qemu_assembly_run): ARM_BRANCH_AND_LINK = f""" +{ARM_PREAMBLE} nop bl func nop @@ -466,18 +481,18 @@ def test_arm_call_instructions(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> nop \n" - " 0x10000004 <_start+4> bl func \n" + " ► 0x200b4 <_start> nop \n" + " 0x200b8 <_start+4> bl func \n" " \n" - " 0x10000008 <_start+8> nop \n" - " 0x1000000c <_start+12> nop \n" - " 0x10000010 mov r0, #0 R0 => 0\n" - " 0x10000014 mov r7, #0xf8 R7 => 0xf8\n" - " 0x10000018 svc #0\n" - " 0x1000001c nop \n" - " 0x10000020 nop \n" - " 0x10000024 nop \n" - " 0x10000028 nop \n" + " 0x200bc <_start+8> nop \n" + " 0x200c0 <_start+12> nop \n" + " 0x200c4 mov r0, #0 R0 => 0\n" + " 0x200c8 mov r7, #0xf8 R7 => 0xf8\n" + " 0x200cc svc #0\n" + " 0x200d0 nop \n" + " 0x200d4 nop \n" + " 0x200d8 nop \n" + " 0x200dc nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -485,6 +500,7 @@ def test_arm_call_instructions(qemu_assembly_run): ARM_STORE = f""" +{ARM_PREAMBLE} ldr r0, =value1 ldr r1, =0x87654321 ldr r2, =0x12345678 @@ -518,24 +534,25 @@ def test_arm_exclusive_store(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr r0, [pc, #0x34] R0, [_start+60] => 0x11094 (value1) ◂— 0\n" - " 0x10000004 <_start+4> ldr r1, [pc, #0x34] R1, [_start+64] => 0x87654321\n" - " 0x10000008 <_start+8> ldr r2, [pc, #0x34] R2, [_start+68] => 0x12345678\n" - " 0x1000000c <_start+12> str r1, [r0] [value1] <= 0x87654321\n" - " 0x10000010 <_start+16> strex r3, r2, [r0] [value1] <= 0x12345678\n" - " 0x10000014 <_start+20> str r1, [r0], #1 [value1] <= 0x87654321\n" - " 0x10000018 <_start+24> add r0, r0, r1 R0 => 0x876653b6 (0x11095 + 0x87654321)\n" - " 0x1000001c <_start+28> nop \n" - " 0x10000020 <_start+32> nop \n" - " 0x10000024 <_start+36> nop \n" - " 0x10000028 <_start+40> nop \n" + " ► 0x200d4 <_start> ldr r0, [pc, #0x34] R0, [_start+60] => 0x3011c (value1) ◂— 0\n" + " 0x200d8 <_start+4> ldr r1, [pc, #0x34] R1, [_start+64] => 0x87654321\n" + " 0x200dc <_start+8> ldr r2, [pc, #0x34] R2, [_start+68] => 0x12345678\n" + " 0x200e0 <_start+12> str r1, [r0] [value1] <= 0x87654321\n" + " 0x200e4 <_start+16> strex r3, r2, [r0] [value1] <= 0x12345678\n" + " 0x200e8 <_start+20> str r1, [r0], #1 [value1] <= 0x87654321\n" + " 0x200ec <_start+24> add r0, r0, r1 R0 => 0x8768443e (0x3011d + 0x87654321)\n" + " 0x200f0 <_start+28> nop \n" + " 0x200f4 <_start+32> nop \n" + " 0x200f8 <_start+36> nop \n" + " 0x200fc <_start+40> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -ARM_SHIFTS = """ +ARM_SHIFTS = f""" +{ARM_PREAMBLE} MOV r0, #3 MOV r1, #0xF000 MOV r2, #0x1234 @@ -562,24 +579,25 @@ def test_arm_logical_shifts(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> mov r0, #3 R0 => 3\n" - " 0x10000004 <_start+4> mov r1, #0xf000 R1 => 0xf000\n" - " 0x10000008 <_start+8> movw r2, #0x1234 R2 => 0x1234\n" - " 0x1000000c <_start+12> lsr r3, r1, #4 R3 => 0xf00 (0xf000 >> 0x4)\n" - " 0x10000010 <_start+16> lsr r4, r1, r0 R4 => 0x1e00 (0xf000 >> 0x3)\n" - " 0x10000014 <_start+20> lsl r5, r4, #4 R5 => 0x1e000 (0x1e00 << 0x4)\n" - " 0x10000018 <_start+24> lsl r6, r4, r2 R6 => 0 (0x1e00 << 0x1234)\n" - " 0x1000001c <_start+28> asr r6, r4, #4 R6 => 0x1e0 (0x1e00 >>s 0x4)\n" - " 0x10000020 <_start+32> asr r6, r4, r0 R6 => 0x3c0 (0x1e00 >>s 0x3)\n" - " 0x10000024 <_start+36> ror r6, r4, #4 R6 => 0x1e0 (0x1e00 >>r 0x4)\n" - " 0x10000028 <_start+40> ror r6, r4, r0 R6 => 0x3c0 (0x1e00 >>r 0x3)\n" + " ► 0x200b4 <_start> mov r0, #3 R0 => 3\n" + " 0x200b8 <_start+4> mov r1, #0xf000 R1 => 0xf000\n" + " 0x200bc <_start+8> movw r2, #0x1234 R2 => 0x1234\n" + " 0x200c0 <_start+12> lsr r3, r1, #4 R3 => 0xf00 (0xf000 >> 0x4)\n" + " 0x200c4 <_start+16> lsr r4, r1, r0 R4 => 0x1e00 (0xf000 >> 0x3)\n" + " 0x200c8 <_start+20> lsl r5, r4, #4 R5 => 0x1e000 (0x1e00 << 0x4)\n" + " 0x200cc <_start+24> lsl r6, r4, r2 R6 => 0 (0x1e00 << 0x1234)\n" + " 0x200d0 <_start+28> asr r6, r4, #4 R6 => 0x1e0 (0x1e00 >>s 0x4)\n" + " 0x200d4 <_start+32> asr r6, r4, r0 R6 => 0x3c0 (0x1e00 >>s 0x3)\n" + " 0x200d8 <_start+36> ror r6, r4, #4 R6 => 0x1e0 (0x1e00 >>r 0x4)\n" + " 0x200dc <_start+40> ror r6, r4, r0 R6 => 0x3c0 (0x1e00 >>r 0x3)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -NEGATIVE_DISPONENTS = r""" +NEGATIVE_DISPONENTS = rf""" +{ARM_PREAMBLE} LDR r1, =msg ADD r1, 4 LDR r0, [r1, #-4] @@ -611,24 +629,25 @@ def test_arm_negative_disponent(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr r1, [pc, #0x24] R1, [_start+44] => 0x11094 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" - " 0x10000004 <_start+4> add r1, r1, #4 R1 => 0x11098 (msg+4) (0x11094 + 0x4)\n" - " 0x10000008 <_start+8> ldr r0, [r1, #-4] R0, [msg] => 0x44434241 ('ABCD')\n" - " 0x1000000c <_start+12> nop \n" - " 0x10000010 <_start+16> nop \n" - " 0x10000014 <_start+20> nop \n" - " 0x10000018 <_start+24> nop \n" - " 0x1000001c <_start+28> nop \n" - " 0x10000020 <_start+32> nop \n" - " 0x10000024 <_start+36> nop \n" - " 0x10000028 <_start+40> nop \n" + " ► 0x200d4 <_start> ldr r1, [pc, #0x24] R1, [_start+44] => 0x30104 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" + " 0x200d8 <_start+4> add r1, r1, #4 R1 => 0x30108 (msg+4) (0x30104 + 0x4)\n" + " 0x200dc <_start+8> ldr r0, [r1, #-4] R0, [msg] => 0x44434241 ('ABCD')\n" + " 0x200e0 <_start+12> nop \n" + " 0x200e4 <_start+16> nop \n" + " 0x200e8 <_start+20> nop \n" + " 0x200ec <_start+24> nop \n" + " 0x200f0 <_start+28> nop \n" + " 0x200f4 <_start+32> nop \n" + " 0x200f8 <_start+36> nop \n" + " 0x200fc <_start+40> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -NEGATIVE_INDEX_REGISTER = r""" +NEGATIVE_INDEX_REGISTER = rf""" +{ARM_PREAMBLE} LDR R1, =msg ADD r1, 4 ADD r2, r1, 4 @@ -655,7 +674,7 @@ msg: def test_arm_negative_index_register(qemu_assembly_run): """ - In the second LDR instruction above, the index register, R2, is negated. + In the LDR instructions above, the index register is negated. This has a specific encoding that has changed in Capstone in the past, so we test to make sure we are handling it correctly. """ @@ -667,24 +686,25 @@ def test_arm_negative_index_register(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> ldr r1, [pc, #0x30] R1, [_start+56] => 0x11094 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" - " 0x10000004 <_start+4> add r1, r1, #4 R1 => 0x11098 (msg+4) (0x11094 + 0x4)\n" - " 0x10000008 <_start+8> add r2, r1, #4 R2 => 0x1109c (msg+8) (0x11098 + 0x4)\n" - " 0x1000000c <_start+12> mov r3, #4 R3 => 4\n" - " 0x10000010 <_start+16> mov r4, #2 R4 => 2\n" - " 0x10000014 <_start+20> ldr r5, [r1, -r3] R5, [msg] => 0x44434241 ('ABCD')\n" - " 0x10000018 <_start+24> ldr r6, [r2, -r4, lsl #2] R6, [msg] => 0x44434241 ('ABCD')\n" - " 0x1000001c <_start+28> nop \n" - " 0x10000020 <_start+32> nop \n" - " 0x10000024 <_start+36> nop \n" - " 0x10000028 <_start+40> nop \n" + " ► 0x200d4 <_start> ldr r1, [pc, #0x30] R1, [_start+56] => 0x30110 (msg) ◂— 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!'\n" + " 0x200d8 <_start+4> add r1, r1, #4 R1 => 0x30114 (msg+4) (0x30110 + 0x4)\n" + " 0x200dc <_start+8> add r2, r1, #4 R2 => 0x30118 (msg+8) (0x30114 + 0x4)\n" + " 0x200e0 <_start+12> mov r3, #4 R3 => 4\n" + " 0x200e4 <_start+16> mov r4, #2 R4 => 2\n" + " 0x200e8 <_start+20> ldr r5, [r1, -r3] R5, [msg] => 0x44434241 ('ABCD')\n" + " 0x200ec <_start+24> ldr r6, [r2, -r4, lsl #2] R6, [msg] => 0x44434241 ('ABCD')\n" + " 0x200f0 <_start+28> nop \n" + " 0x200f4 <_start+32> nop \n" + " 0x200f8 <_start+36> nop \n" + " 0x200fc <_start+40> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -ARM_IT_BLOCK = """ +ARM_IT_BLOCK = f""" +{ARM_PREAMBLE} add r0, pc, #1 bx r0 @@ -723,17 +743,17 @@ def test_arm_it_block(qemu_assembly_run): expected_1 = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────[ DISASM / arm / thumb mode / set emulate on ]─────────────────\n" - " ► 0x10000008 <_start+8> cmp r0, #0 0x10000009 - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" - " 0x1000000a <_start+10> ittte eq\n" - " 0x1000000c <_start+12> movs r1, #1 R1 => 1\n" - " 0x1000000e <_start+14> movs r2, #2 R2 => 2\n" - " 0x10000010 <_start+16> movs r2, #3 R2 => 3\n" - " 0x10000012 <_start+18> movs r1, #4 R1 => 4\n" - " 0x10000014 <_start+20> nop \n" - " 0x10000016 <_start+22> nop \n" - " 0x10000018 <_start+24> nop \n" - " 0x1000001a <_start+26> nop \n" - " 0x1000001c <_start+28> nop \n" + " ► 0x200bc <_start+8> cmp r0, #0 0x200bd - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" + " 0x200be <_start+10> ittte eq\n" + " 0x200c0 <_start+12> movs r1, #1 R1 => 1\n" + " 0x200c2 <_start+14> movs r2, #2 R2 => 2\n" + " 0x200c4 <_start+16> movs r2, #3 R2 => 3\n" + " 0x200c6 <_start+18> movs r1, #4 R1 => 4\n" + " 0x200c8 <_start+20> nop \n" + " 0x200ca <_start+22> nop \n" + " 0x200cc <_start+24> nop \n" + " 0x200ce <_start+26> nop \n" + " 0x200d0 <_start+28> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -750,17 +770,17 @@ def test_arm_it_block(qemu_assembly_run): expected_2 = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "─────────────────[ DISASM / arm / thumb mode / set emulate on ]─────────────────\n" - " 0x10000008 <_start+8> cmp r0, #0 0x10000009 - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" - " 0x1000000a <_start+10> ittte eq\n" - " 0x1000000c <_start+12> movs r1, #1 R1 => 1\n" - " ► 0x1000000e <_start+14> movs r2, #2 R2 => 2\n" - " 0x10000010 <_start+16> movs r2, #3 R2 => 3\n" - " 0x10000012 <_start+18> movs r1, #4 R1 => 4\n" - " 0x10000014 <_start+20> nop \n" - " 0x10000016 <_start+22> nop \n" - " 0x10000018 <_start+24> nop \n" - " 0x1000001a <_start+26> nop \n" - " 0x1000001c <_start+28> nop \n" + " 0x200bc <_start+8> cmp r0, #0 0x200bd - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" + " 0x200be <_start+10> ittte eq\n" + " 0x200c0 <_start+12> movs r1, #1 R1 => 1\n" + " ► 0x200c2 <_start+14> movs r2, #2 R2 => 2\n" + " 0x200c4 <_start+16> movs r2, #3 R2 => 3\n" + " 0x200c6 <_start+18> movs r1, #4 R1 => 4\n" + " 0x200c8 <_start+20> nop \n" + " 0x200ca <_start+22> nop \n" + " 0x200cc <_start+24> nop \n" + " 0x200ce <_start+26> nop \n" + " 0x200d0 <_start+28> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -770,30 +790,30 @@ def test_arm_it_block(qemu_assembly_run): def test_arm_it_block_cached_thumb_mode(qemu_assembly_run): """ This test ensures that we handle transitions to Thumb mode correctly once the emulator has been disabled. + + Emulation is disabled internally at the "ittte" instruction. """ qemu_assembly_run(ARM_IT_BLOCK, "arm") - gdb.execute("context disasm", to_string=True) - dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────[ DISASM / arm / arm mode / set emulate on ]──────────────────\n" - " ► 0x10000000 <_start> add r0, pc, #1 R0 => 0x10000009 (_start+9) (0x10000008 + 0x1)\n" - " 0x10000004 <_start+4> bx r0 <_start+8>\n" + " ► 0x200b4 <_start> add r0, pc, #1 R0 => 0x200bd (_start+9) (0x200bc + 0x1)\n" + " 0x200b8 <_start+4> bx r0 <_start+8>\n" " ↓\n" - " 0x10000008 <_start+8> cmp r0, #0 0x10000009 - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" - " 0x1000000a <_start+10> ittte eq\n" - " 0x1000000c <_start+12> movs r1, #1 R1 => 1\n" - " 0x1000000e <_start+14> movs r2, #2 R2 => 2\n" - " 0x10000010 <_start+16> movs r2, #3 R2 => 3\n" - " 0x10000012 <_start+18> movs r1, #4 R1 => 4\n" - " 0x10000014 <_start+20> nop \n" - " 0x10000016 <_start+22> nop \n" - " 0x10000018 <_start+24> nop \n" + " 0x200bc <_start+8> cmp r0, #0 0x200bd - 0x0 CPSR => 0x20000030 [ n z C v q j T e a i f ]\n" + " 0x200be <_start+10> ittte eq\n" + " 0x200c0 <_start+12> movs r1, #1 R1 => 1\n" + " 0x200c2 <_start+14> movs r2, #2 R2 => 2\n" + " 0x200c4 <_start+16> movs r2, #3 R2 => 3\n" + " 0x200c6 <_start+18> movs r1, #4 R1 => 4\n" + " 0x200c8 <_start+20> nop \n" + " 0x200ca <_start+22> nop \n" + " 0x200cc <_start+24> nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) diff --git a/tests/qemu-tests/tests/user/test_basic.py b/tests/qemu-tests/tests/user/test_basic.py index 283a9229b..ea4201e57 100644 --- a/tests/qemu-tests/tests/user/test_basic.py +++ b/tests/qemu-tests/tests/user/test_basic.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Literal - import gdb import user @@ -18,15 +16,10 @@ NUMBER_OF_STEPS = 1500 # Step through a binary, running "ctx" each time the program stops # This is meant to detect crashes originating from the annotations/emulation code -def helper( - qemu_start_binary, filename: str, qemu_arch: str, endian: Literal["big", "little"] | None = None -): +def helper(qemu_start_binary, filename: str, arch: str): FILE = user.binaries.get(filename) - qemu_start_binary(FILE, qemu_arch, endian) - - gdb.execute("b main") - gdb.execute("c") + qemu_start_binary(FILE, arch) pwndbg.commands.context.context_disasm() @@ -51,12 +44,12 @@ def test_basic_riscv64(qemu_start_binary): def test_basic_mips64(qemu_start_binary): # pwnlib.context.endian defaults to "little", but these MIPS binaries are compiled to big endian. - helper(qemu_start_binary, "basic.mips64.out", "mips64", endian="big") + helper(qemu_start_binary, "basic.mips64.out", "mips64") def test_basic_mips32(qemu_start_binary): - helper(qemu_start_binary, "basic.mips32.out", "mips", endian="big") + helper(qemu_start_binary, "basic.mips32.out", "mips32") def test_basic_mipsel32(qemu_start_binary): - helper(qemu_start_binary, "basic.mipsel32.out", "mips", endian="little") + helper(qemu_start_binary, "basic.mipsel32.out", "mipsel32") diff --git a/tests/qemu-tests/tests/user/test_mips.py b/tests/qemu-tests/tests/user/test_mips.py index e01775f6d..8c6067f0d 100644 --- a/tests/qemu-tests/tests/user/test_mips.py +++ b/tests/qemu-tests/tests/user/test_mips.py @@ -5,6 +5,13 @@ import pytest import pwndbg.color +# Zig requires the start symbol to be __start instead of _start for MIPS +MIPS_PREAMBLE = """ +.text +.globl __start +__start: +""" + MIPS_GRACEFUL_EXIT = """ li $v0, 0xfa1 li $a0, 0 @@ -20,6 +27,8 @@ syscall MIPS_DELAY_SLOT = f""" +{MIPS_PREAMBLE} + beq $t1, $t0, _target nop @@ -32,8 +41,8 @@ end: """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_delay_slot(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_delay_slot(qemu_assembly_run, arch): """ MIPS has delay slots, meaning that when a branch is encountered, they is a "delay" in the branch taking effect. The next instruction sequentially in memory is always executed, and then the result of the branch is applied. @@ -42,7 +51,7 @@ def test_mips32_delay_slot(qemu_assembly_run, endian): This test makes sure that looking forwards, we determine branch slots directly, and after moving passed them, they stay intact. """ - qemu_assembly_run(MIPS_DELAY_SLOT, "mips", endian=endian) + qemu_assembly_run(MIPS_DELAY_SLOT, arch) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -50,14 +59,14 @@ def test_mips32_delay_slot(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> ✔ beq $t1, $t0, _target <_target>\n" - " 0x10000004 <_start+4> nop \n" + " ► 0x20150 <__start> ✔ beq $t1, $t0, _target <_target>\n" + " 0x20154 <__start+4> nop \n" " ↓\n" - " 0x10000008 <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n" - " 0x1000000c <_target+4> nop \n" - " 0x10000010 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" - " 0x10000014 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" - " 0x10000018 syscall \n" + " 0x2015c <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n" + " 0x20160 <_target+4> nop \n" + " 0x20164 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" + " 0x20168 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" + " 0x2016c syscall \n" "\n" "\n" "\n" @@ -75,14 +84,14 @@ def test_mips32_delay_slot(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " 0x10000000 <_start> ✔ beq $t1, $t0, _target <_target>\n" - " 0x10000004 <_start+4> nop \n" + " 0x20150 <__start> ✔ beq $t1, $t0, _target <_target>\n" + " 0x20154 <__start+4> nop \n" " ↓\n" - " ► 0x10000008 <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n" - " 0x1000000c <_target+4> nop \n" - " 0x10000010 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" - " 0x10000014 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" - " 0x10000018 syscall \n" + " ► 0x2015c <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n" + " 0x20160 <_target+4> nop \n" + " 0x20164 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" + " 0x20168 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" + " 0x2016c syscall \n" "\n" "\n" "\n" @@ -93,6 +102,8 @@ def test_mips32_delay_slot(qemu_assembly_run, endian): MIPS_BNEZ = f""" +{MIPS_PREAMBLE} + li $t0, 10 bnez $t0, end nop @@ -104,12 +115,12 @@ end: """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_bnez_instruction(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_bnez_instruction(qemu_assembly_run, arch): """ Test that conditional branches work, with and without emulation. """ - qemu_assembly_run(MIPS_BNEZ, "mips", endian=endian) + qemu_assembly_run(MIPS_BNEZ, arch) dis_1 = gdb.execute("context disasm", to_string=True) dis_1 = pwndbg.color.strip(dis_1) @@ -117,13 +128,13 @@ def test_mips32_bnez_instruction(qemu_assembly_run, endian): expected_1 = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" - " 0x10000004 <_start+4> ✔ bnez $t0, end \n" - " 0x10000008 <_start+8> nop \n" + " ► 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" + " 0x20154 <__start+4> ✔ bnez $t0, end \n" + " 0x20158 <__start+8> nop \n" " ↓\n" - " 0x10000014 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" - " 0x10000018 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" - " 0x1000001c syscall \n" + " 0x20168 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" + " 0x2016c addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" + " 0x20170 syscall \n" "\n" "\n" "\n" @@ -142,16 +153,16 @@ def test_mips32_bnez_instruction(qemu_assembly_run, endian): expected_2 = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────────[ DISASM / mips / set emulate off ]───────────────────────\n" - " ► 0x10000000 <_start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n" - " 0x10000004 <_start+4> bnez $t0, end \n" - " 0x10000008 <_start+8> nop \n" + " ► 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n" + " 0x20154 <__start+4> bnez $t0, end \n" + " 0x20158 <__start+8> nop \n" " \n" - " 0x1000000c <_start+12> nop \n" - " 0x10000010 <_start+16> nop \n" - " 0x10000014 addiu $v0, $zero, 0xfa1\n" - " 0x10000018 addiu $a0, $zero, 0\n" - " 0x1000001c syscall \n" - "\n" + " 0x2015c <__start+12> nop \n" + " 0x20160 <__start+16> nop \n" + " 0x20164 <__start+20> nop \n" + " 0x20168 addiu $v0, $zero, 0xfa1\n" + " 0x2016c addiu $a0, $zero, 0\n" + " 0x20170 syscall \n" "\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -167,13 +178,13 @@ def test_mips32_bnez_instruction(qemu_assembly_run, endian): expected_3 = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "──────────────────────[ DISASM / mips / set emulate off ]───────────────────────\n" - " 0x10000000 <_start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n" - " ► 0x10000004 <_start+4> ✔ bnez $t0, end \n" - " 0x10000008 <_start+8> nop \n" + " 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n" + " ► 0x20154 <__start+4> ✔ bnez $t0, end \n" + " 0x20158 <__start+8> nop \n" " ↓\n" - " 0x10000014 addiu $v0, $zero, 0xfa1\n" - " 0x10000018 addiu $a0, $zero, 0\n" - " 0x1000001c syscall \n" + " 0x20168 addiu $v0, $zero, 0xfa1\n" + " 0x2016c addiu $a0, $zero, 0\n" + " 0x20170 syscall \n" "\n" "\n" "\n" @@ -185,6 +196,8 @@ def test_mips32_bnez_instruction(qemu_assembly_run, endian): MIPS_CALL = f""" +{MIPS_PREAMBLE} + jal my_function nop j end @@ -198,15 +211,15 @@ end: """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_call_instruction(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_call_instruction(qemu_assembly_run, arch): """ Ensure that MIPS "branch-and-link" instructions like "JAL" do not get unrolled, and have splits in disassembly correctly. There's a bug in Capstone which doesn't consider JAL a jump-like/call instruction, so we have to manually add the jump group. See: https://github.com/capstone-engine/capstone/issues/2448 """ - qemu_assembly_run(MIPS_CALL, "mips", endian=endian) + qemu_assembly_run(MIPS_CALL, arch) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -214,25 +227,29 @@ def test_mips32_call_instruction(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> jal my_function \n" + " ► 0x20150 <__start> jal my_function \n" " $a0: 0\n" " $a1: 0\n" " $a2: 0\n" " $a3: 0\n" - " 0x10000004 <_start+4> nop \n" + " 0x20154 <__start+4> nop \n" " \n" - " 0x10000008 <_start+8> j end \n" - " 0x1000000c <_start+12> nop \n" + " 0x20158 <__start+8> nop \n" + " 0x2015c <__start+12> j end \n" + " 0x20160 <__start+16> nop \n" " ↓\n" - " 0x10000014 addiu $v0, $zero, 0xfa1\n" - " 0x10000018 addiu $a0, $zero, 0\n" - " 0x1000001c syscall \n" + " 0x20170 addiu $v0, $zero, 0xfa1\n" + " 0x20174 addiu $a0, $zero, 0\n" + " 0x20178 syscall \n" "────────────────────────────────────────────────────────────────────────────────\n" ) + assert dis == expected + # Step to "end" gdb.execute("ni", to_string=True) gdb.execute("si", to_string=True) + gdb.execute("si", to_string=True) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -240,16 +257,16 @@ def test_mips32_call_instruction(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " 0x10000000 <_start> jal my_function \n" - " 0x10000004 <_start+4> nop \n" + " 0x20150 <__start> jal my_function \n" + " 0x20154 <__start+4> nop \n" " \n" - " 0x10000008 <_start+8> j end \n" - " 0x1000000c <_start+12> nop \n" + " 0x20158 <__start+8> nop \n" + " 0x2015c <__start+12> j end \n" + " 0x20160 <__start+16> nop \n" " ↓\n" - " ► 0x10000014 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" - " 0x10000018 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" - " 0x1000001c syscall \n" - "\n" + " ► 0x20170 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" + " 0x20174 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" + " 0x20178 syscall \n" "\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -257,7 +274,9 @@ def test_mips32_call_instruction(qemu_assembly_run, endian): assert dis == expected -MIPS_STORE_INSTRUCTIONS = """ +MIPS_STORE_INSTRUCTIONS = f""" +{MIPS_PREAMBLE} + li $t0, 0x12345678 la $s0, value1 @@ -271,19 +290,19 @@ sb $t0, 0($s2) .data value1: .word 0 -value2: .half 0 +value2: .short 0 value3: .byte 0 """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_store_instruction(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_store_instruction(qemu_assembly_run, arch): """ Ensure all store instructions are annotated correctly. The assembly is very specific - note the .data section and the size of the variables. """ - qemu_assembly_run(MIPS_STORE_INSTRUCTIONS, "mips", endian=endian) + qemu_assembly_run(MIPS_STORE_INSTRUCTIONS, arch) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -291,24 +310,26 @@ def test_mips32_store_instruction(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> lui $t0, 0x1234 T0 => 0x12340000\n" - " 0x10000004 <_start+4> ori $t0, $t0, 0x5678 T0 => 0x12345678 (0x12340000 | 0x5678)\n" - " 0x10000008 <_start+8> lui $s0, 0x40 S0 => 0x400000\n" - " 0x1000000c <_start+12> addiu $s0, $s0, 0x1130 S0 => 0x401130 (value1) (0x400000 + 0x1130)\n" - " 0x10000010 <_start+16> sw $t0, 0($s0) [value1] <= 0x12345678\n" - " 0x10000014 <_start+20> lui $s1, 0x40 S1 => 0x400000\n" - " 0x10000018 <_start+24> addiu $s1, $s1, 0x1134 S1 => 0x401134 (value2) (0x400000 + 0x1134)\n" - " 0x1000001c <_start+28> sh $t0, 0($s1) [value2] <= 0x5678\n" - " 0x10000020 <_start+32> lui $s2, 0x40 S2 => 0x400000\n" - " 0x10000024 <_start+36> addiu $s2, $s2, 0x1136 S2 => 0x401136 (value3) (0x400000 + 0x1136)\n" - " 0x10000028 <_start+40> sb $t0, 0($s2) [value3] <= 0x78\n" + " ► 0x20150 <__start> lui $t0, 0x1234 T0 => 0x12340000\n" + " 0x20154 <__start+4> ori $t0, $t0, 0x5678 T0 => 0x12345678 (0x12340000 | 0x5678)\n" + " 0x20158 <__start+8> lui $s0, 3 S0 => 0x30000\n" + " 0x2015c <__start+12> addiu $s0, $s0, 0x180 S0 => 0x30180 (value1) (0x30000 + 0x180)\n" + " 0x20160 <__start+16> sw $t0, 0($s0) [value1] <= 0x12345678\n" + " 0x20164 <__start+20> lui $s1, 3 S1 => 0x30000\n" + " 0x20168 <__start+24> addiu $s1, $s1, 0x184 S1 => 0x30184 (value2) (0x30000 + 0x184)\n" + " 0x2016c <__start+28> sh $t0, 0($s1) [value2] <= 0x5678\n" + " 0x20170 <__start+32> lui $s2, 3 S2 => 0x30000\n" + " 0x20174 <__start+36> addiu $s2, $s2, 0x186 S2 => 0x30186 (value3) (0x30000 + 0x186)\n" + " 0x20178 <__start+40> sb $t0, 0($s2) [value3] <= 0x78\n" "────────────────────────────────────────────────────────────────────────────────\n" ) assert dis == expected -MIPS_LOAD_INSTRUCTIONS = """ +MIPS_LOAD_INSTRUCTIONS = f""" +{MIPS_PREAMBLE} + li $t0, 0xFFFFFFFF la $s0, value1 @@ -340,13 +361,13 @@ loads: .data value1: .word 0 -value2: .half 0 +value2: .short 0 value3: .byte 0 """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_load_instructions(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_load_instructions(qemu_assembly_run, arch): """ This test ensures our logic for load instructions - including sign-extension - is working correctly. @@ -354,7 +375,7 @@ def test_mips32_load_instructions(qemu_assembly_run, endian): The signed reads should signed extend from the read size to 32-bits. """ - qemu_assembly_run(MIPS_LOAD_INSTRUCTIONS, "mips", endian=endian) + qemu_assembly_run(MIPS_LOAD_INSTRUCTIONS, arch) gdb.execute("b loads") gdb.execute("c") @@ -365,12 +386,12 @@ def test_mips32_load_instructions(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000038 lw $t1, 0($s0) T1, [value1] => 0xffffffff\n" - " 0x1000003c lhu $t2, 0($s1) T2, [value2] => 0xffff\n" - " 0x10000040 lbu $t3, 0($s2) T3, [value3] => 0xff\n" - " 0x10000044 lw $t4, 0($s0) T4, [value1] => 0xffffffff\n" - " 0x10000048 lh $t5, 0($s1) T5, [value2] => 0xffffffff\n" - " 0x1000004c lb $t6, 0($s2) T6, [value3] => 0xffffffff\n" + " ► 0x20188 lw $t1, 0($s0) T1, [value1] => 0xffffffff\n" + " 0x2018c lhu $t2, 0($s1) T2, [value2] => 0xffff\n" + " 0x20190 lbu $t3, 0($s2) T3, [value3] => 0xff\n" + " 0x20194 lw $t4, 0($s0) T4, [value1] => 0xffffffff\n" + " 0x20198 lh $t5, 0($s1) T5, [value2] => 0xffffffff\n" + " 0x2019c lb $t6, 0($s2) T6, [value3] => 0xffffffff\n" "\n" "\n" "\n" @@ -382,7 +403,9 @@ def test_mips32_load_instructions(qemu_assembly_run, endian): assert dis == expected -MIPS_BINARY_OPERATIONS = """ +MIPS_BINARY_OPERATIONS = f""" +{MIPS_PREAMBLE} + li $t0, 10 li $t1, 20 @@ -398,9 +421,9 @@ srlv $t3, $t8, $t5 """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_binary_operations(qemu_assembly_run, endian): - qemu_assembly_run(MIPS_BINARY_OPERATIONS, "mips", endian=endian) +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_binary_operations(qemu_assembly_run, arch): + qemu_assembly_run(MIPS_BINARY_OPERATIONS, arch) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -408,17 +431,17 @@ def test_mips32_binary_operations(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" - " 0x10000004 <_start+4> addiu $t1, $zero, 0x14 T1 => 20 (0x0 + 0x14)\n" - " 0x10000008 <_start+8> add $t2, $t0, $t1 T2 => 30 (0xa + 0x14)\n" - " 0x1000000c <_start+12> sub $t3, $t1, $t0 T3 => 10 (0x14 - 0xa)\n" - " 0x10000010 <_start+16> and $t4, $t0, $t1 T4 => 0 (0xa & 0x14)\n" - " 0x10000014 <_start+20> or $t5, $t0, $t1 T5 => 30 (0xa | 0x14)\n" - " 0x10000018 <_start+24> xor $t6, $t0, $t1 T6 => 30 (0xa ^ 0x14)\n" - " 0x1000001c <_start+28> sll $t7, $t0, 2 T7 => 40 (0xa << 0x2)\n" - " 0x10000020 <_start+32> srl $t8, $t1, 2 T8 => 5 (0x14 >> 0x2)\n" - " 0x10000024 <_start+36> sllv $t8, $t1, $t8 T8 => 0x280 (0x14 << 0x5)\n" - " 0x10000028 <_start+40> srlv $t3, $t8, $t5 T3 => 0 (0x280 >> 0x1e)\n" + " ► 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" + " 0x20154 <__start+4> addiu $t1, $zero, 0x14 T1 => 20 (0x0 + 0x14)\n" + " 0x20158 <__start+8> add $t2, $t0, $t1 T2 => 30 (0xa + 0x14)\n" + " 0x2015c <__start+12> sub $t3, $t1, $t0 T3 => 10 (0x14 - 0xa)\n" + " 0x20160 <__start+16> and $t4, $t0, $t1 T4 => 0 (0xa & 0x14)\n" + " 0x20164 <__start+20> or $t5, $t0, $t1 T5 => 30 (0xa | 0x14)\n" + " 0x20168 <__start+24> xor $t6, $t0, $t1 T6 => 30 (0xa ^ 0x14)\n" + " 0x2016c <__start+28> sll $t7, $t0, 2 T7 => 40 (0xa << 0x2)\n" + " 0x20170 <__start+32> srl $t8, $t1, 2 T8 => 5 (0x14 >> 0x2)\n" + " 0x20174 <__start+36> sllv $t8, $t1, $t8 T8 => 0x280 (0x14 << 0x5)\n" + " 0x20178 <__start+40> srlv $t3, $t8, $t5 T3 => 0 (0x280 >> 0x1e)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -426,6 +449,8 @@ def test_mips32_binary_operations(qemu_assembly_run, endian): MIPS_JUMPS = f""" +{MIPS_PREAMBLE} + nop beq $t1, $t0, first nop @@ -447,12 +472,12 @@ end: """ -@pytest.mark.parametrize("endian", ["big", "little"]) -def test_mips32_multiple_branches_followed(qemu_assembly_run, endian): +@pytest.mark.parametrize("arch", ["mips32", "mipsel32"]) +def test_mips32_multiple_branches_followed(qemu_assembly_run, arch): """ Ensure that emulation is setup correctly so as to follow multiple branches - bugs in how we handle delay slots and disable the emulator might break this. """ - qemu_assembly_run(MIPS_JUMPS, "mips", endian=endian) + qemu_assembly_run(MIPS_JUMPS, arch) dis = gdb.execute("context disasm", to_string=True) dis = pwndbg.color.strip(dis) @@ -460,20 +485,20 @@ def test_mips32_multiple_branches_followed(qemu_assembly_run, endian): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / mips / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> nop \n" - " 0x10000004 <_start+4> ✔ beq $t1, $t0, first \n" - " 0x10000008 <_start+8> nop \n" + " ► 0x20150 <__start> nop \n" + " 0x20154 <__start+4> ✔ beq $t1, $t0, first \n" + " 0x20158 <__start+8> nop \n" " ↓\n" - " 0x10000010 addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" - " 0x10000014 ✔ bnez $t0, second \n" - " 0x10000018 nop \n" + " 0x20164 addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n" + " 0x20168 ✔ bnez $t0, second \n" + " 0x2016c nop \n" " ↓\n" - " 0x10000020 b end \n" - " 0x10000024 nop \n" + " 0x20178 b end \n" + " 0x2017c nop \n" " ↓\n" - " 0x1000002c addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" - " 0x10000030 addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" - " 0x10000034 syscall \n" + " 0x20188 addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n" + " 0x2018c addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n" + " 0x20190 syscall \n" "────────────────────────────────────────────────────────────────────────────────\n" ) diff --git a/tests/qemu-tests/tests/user/test_riscv64.py b/tests/qemu-tests/tests/user/test_riscv64.py index 239e1d19b..cf4d7261a 100644 --- a/tests/qemu-tests/tests/user/test_riscv64.py +++ b/tests/qemu-tests/tests/user/test_riscv64.py @@ -7,6 +7,12 @@ import pwndbg.aglib.symbol import pwndbg.color import pwndbg.dbg +RISCV64_PREAMBLE = """ +.text +.globl _start +_start: +""" + RISCV64_GRACEFUL_EXIT = """ li a2, 30 li a7, 93 @@ -15,6 +21,7 @@ RISCV64_GRACEFUL_EXIT = """ """ RISCV64_JALR = f""" +{RISCV64_PREAMBLE} li a0, 10 li a1, 20 @@ -49,19 +56,19 @@ def test_riscv64_jalr(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / rv64 / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> c.li a0, 0xa A0 => 0xa\n" - " 0x10000002 <_start+2> c.li a1, 0x14 A1 => 0x14\n" - " 0x10000004 <_start+4> auipc t0, 0 T0 => 0x10000004 (_start+4)\n" - " 0x10000008 <_start+8> addi t0, t0, 0x20 T0 => 0x10000024 (function) (0x10000004 + 0x20)\n" - " 0x1000000c <_start+12> jalr t0 \n" + " ► 0x1001158 <_start> c.li a0, 0xa A0 => 0xa\n" + " 0x100115a <_start+2> c.li a1, 0x14 A1 => 0x14\n" + " 0x100115c <_start+4> auipc t0, 0 T0 => 0x100115c (_start+4)\n" + " 0x1001160 <_start+8> addi t0, t0, 0x1c T0 => 0x1001178 (function) (0x100115c + 0x1c)\n" + " 0x1001164 <_start+12> c.jalr t0 \n" " \n" - " 0x10000010 <_start+16> add a2, a0, a1\n" - " 0x10000014 <_start+20> auipc t1, 0 T1 => 0x10000014 (_start+20)\n" - " 0x10000018 <_start+24> addi t1, t1, 0x12\n" - " 0x1000001c <_start+28> jalr t1\n" + " 0x1001166 <_start+14> add a2, a0, a1\n" + " 0x100116a <_start+18> auipc t1, 0 T1 => 0x100116a (_start+18)\n" + " 0x100116e <_start+22> addi t1, t1, 0x10\n" + " 0x1001172 <_start+26> c.jalr t1\n" " \n" - " 0x10000020 <_start+32> c.nop \n" - " 0x10000022 <_start+34> c.nop \n" + " 0x1001174 <_start+28> c.nop \n" + " 0x1001176 <_start+30> c.nop \n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -69,6 +76,7 @@ def test_riscv64_jalr(qemu_assembly_run): RISCV64_COMPRESSED_LOAD_STORE = f""" +{RISCV64_PREAMBLE} li a0, 0x1234567890ABCDEF la a2, data @@ -118,17 +126,17 @@ def test_riscv64_compressed_loads(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / rv64 / set emulate on ]───────────────────────\n" - " ► 0x10000028 c.sd a0, 0(a2) [data] <= 0x1234567890abcdef\n" - " 0x1000002a c.ld a1, 0(a2) A1, [data] => 0x1234567890abcdef\n" - " 0x1000002c c.li a1, 0x10 A1 => 0x10\n" - " 0x1000002e addi a2, zero, 0x26 A2 => 38 (0x0 + 0x26)\n" - " 0x10000032 add a4, a1, a2 A4 => 54 (0x10 + 0x26)\n" - " 0x10000036 sub a5, a1, a3 A5 => 16 (0x10 - 0x0)\n" - " 0x1000003a xor a6, a1, a2 A6 => 54 (0x10 ^ 0x26)\n" - " 0x1000003e and a7, a1, a2 A7 => 0 (0x10 & 0x26)\n" - " 0x10000042 sll a3, a1, a2 A3 => 0x40000000000 (0x10 << 0x26)\n" - " 0x10000046 mul a2, a1, a2 A2 => 0x260 (0x10 * 0x26)\n" - " 0x1000004a div a5, a3, a2 A5 => 0x1af286bca (0x40000000000 / 0x260)\n" + " ► 0x10011b8 c.sd a0, 0(a2) [data] <= 0x1234567890abcdef\n" + " 0x10011ba c.ld a1, 0(a2) A1, [data] => 0x1234567890abcdef\n" + " 0x10011bc c.li a1, 0x10 A1 => 0x10\n" + " 0x10011be addi a2, zero, 0x26 A2 => 38 (0x0 + 0x26)\n" + " 0x10011c2 add a4, a1, a2 A4 => 54 (0x10 + 0x26)\n" + " 0x10011c6 sub a5, a1, a3 A5 => 16 (0x10 - 0x0)\n" + " 0x10011ca xor a6, a1, a2 A6 => 54 (0x10 ^ 0x26)\n" + " 0x10011ce and a7, a1, a2 A7 => 0 (0x10 & 0x26)\n" + " 0x10011d2 sll a3, a1, a2 A3 => 0x40000000000 (0x10 << 0x26)\n" + " 0x10011d6 mul a2, a1, a2 A2 => 0x260 (0x10 * 0x26)\n" + " 0x10011da div a5, a3, a2 A5 => 0x1af286bca (0x40000000000 / 0x260)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -136,6 +144,7 @@ def test_riscv64_compressed_loads(qemu_assembly_run): RISCV64_JUMPS = f""" +{RISCV64_PREAMBLE} li t0, 4 li t1, 5 beq t0, t1, first @@ -174,22 +183,22 @@ def test_riscv64_jumps(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / rv64 / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> c.li t0, 4 T0 => 4\n" - " 0x10000002 <_start+2> c.li t1, 5 T1 => 5\n" - " 0x10000004 <_start+4> beq t0, t1, 6 \n" + " ► 0x1001158 <_start> c.li t0, 4 T0 => 4\n" + " 0x100115a <_start+2> c.li t1, 5 T1 => 5\n" + " 0x100115c <_start+4> beq t0, t1, 6 \n" " \n" - " 0x10000008 <_start+8> c.nop \n" - " 0x1000000a ✔ bne t0, t2, 6 \n" + " 0x1001160 <_start+8> c.nop \n" + " 0x1001162 ✔ bne t0, t2, 6 \n" " ↓\n" - " 0x10000010 blt t0, t3, 6 \n" + " 0x1001168 blt t0, t3, 6 \n" " \n" - " 0x10000014 c.nop \n" - " 0x10000016 ✔ bge t0, t4, 6 \n" + " 0x100116c c.nop \n" + " 0x100116e ✔ bge t0, t4, 6 \n" " ↓\n" - " 0x1000001c ✔ blt t5, t0, 6 \n" + " 0x1001174 ✔ blt t5, t0, 6 \n" " ↓\n" - " 0x10000022 c.li a2, 0x1e A2 => 0x1e\n" - " 0x10000024 addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" + " 0x100117a c.li a2, 0x1e A2 => 0x1e\n" + " 0x100117c addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -205,22 +214,22 @@ def test_riscv64_jumps(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / rv64 / set emulate on ]───────────────────────\n" - " 0x10000002 <_start+2> c.li t1, 5 T1 => 5\n" - " 0x10000004 <_start+4> beq t0, t1, 6 \n" + " 0x100115a <_start+2> c.li t1, 5 T1 => 5\n" + " 0x100115c <_start+4> beq t0, t1, 6 \n" " \n" - " 0x10000008 <_start+8> c.nop \n" - " 0x1000000a ✔ bne t0, t2, 6 \n" + " 0x1001160 <_start+8> c.nop \n" + " 0x1001162 ✔ bne t0, t2, 6 \n" " ↓\n" - " 0x10000010 blt t0, t3, 6 \n" + " 0x1001168 blt t0, t3, 6 \n" " \n" - " ► 0x10000014 c.nop \n" - " 0x10000016 ✔ bge t0, t4, 6 \n" + " ► 0x100116c c.nop \n" + " 0x100116e ✔ bge t0, t4, 6 \n" " ↓\n" - " 0x1000001c ✔ blt t5, t0, 6 \n" + " 0x1001174 ✔ blt t5, t0, 6 \n" " ↓\n" - " 0x10000022 c.li a2, 0x1e A2 => 0x1e\n" - " 0x10000024 addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" - " 0x10000028 c.li a0, 0 A0 => 0\n" + " 0x100117a c.li a2, 0x1e A2 => 0x1e\n" + " 0x100117c addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" + " 0x1001180 c.li a0, 0 A0 => 0\n" "────────────────────────────────────────────────────────────────────────────────\n" ) @@ -228,6 +237,7 @@ def test_riscv64_jumps(qemu_assembly_run): RISCV64_JUMP_CHAIN = f""" +{RISCV64_PREAMBLE} j a a: @@ -265,23 +275,23 @@ def test_riscv64_jump_chain(qemu_assembly_run): expected = ( "LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA\n" "───────────────────────[ DISASM / rv64 / set emulate on ]───────────────────────\n" - " ► 0x10000000 <_start> c.j 2 \n" + " ► 0x1001158 <_start> c.j 2 \n" " ↓\n" - " 0x10000002 c.j 2 \n" + " 0x100115a c.j 2 \n" " ↓\n" - " 0x10000004 c.j 2 \n" + " 0x100115c c.j 2 \n" " ↓\n" - " 0x10000006 c.j 2 \n" + " 0x100115e c.j 2 \n" " ↓\n" - " 0x10000008 c.j 2 \n" + " 0x1001160 c.j 2 \n" " ↓\n" - " 0x1000000a c.j 2 \n" + " 0x1001162 c.j 2 \n" " ↓\n" - " 0x1000000c c.li a2, 0x1e A2 => 0x1e\n" - " 0x1000000e addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" - " 0x10000012 c.li a0, 0 A0 => 0\n" - " 0x10000014 ecall \n" - " 0x10000018 c.addiw s6, -0x10\n" + " 0x1001164 c.li a2, 0x1e A2 => 0x1e\n" + " 0x1001166 addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n" + " 0x100116a c.li a0, 0 A0 => 0\n" + " 0x100116c ecall \n" + " 0x1001170 c.addiw s6, -0x10\n" "────────────────────────────────────────────────────────────────────────────────\n" ) diff --git a/tests/tests.py b/tests/tests.py index ac8c22d68..9456fbb64 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -304,20 +304,31 @@ def main(): sys.exit(1) else: gdbinit_path = os.path.join(root_dir, "gdbinit.py") - gdb_binary = "gdb" - if args.type == "cross-arch": - gdb_binary = "gdb-multiarch" - gdb_path = shutil.which(gdb_binary) + if args.type == "gdb": + gdb_path = shutil.which("gdb") + elif args.type == "cross-arch": + if (gdb_multiarch := shutil.which("gdb-multiarch")) is not None: + gdb_path = gdb_multiarch + else: + supports_arches = "py import os; archs = ['i386', 'aarch64', 'arm', 'mips', 'riscv', 'sparc']; os._exit(3) if len([arch for arch in archs if arch in gdb.architecture_names()]) == len(archs) else os._exit(2)" + + result = run_gdb("gdb", ["-ex", supports_arches]) + # GDB supports cross architecture targets + if result.returncode == 3: + gdb_path = shutil.which("gdb") + else: + raise Exception( + "gdb-multiarch not found, and gdb does not support cross architecture targets" + ) os.environ["GDB_INIT_PATH"] = gdbinit_path os.environ["GDB_BIN_PATH"] = gdb_path test_dir_path = TEST_FOLDER_NAME[args.type] - if args.type == "gdb": - ensure_zig_path() - make_binaries(test_dir_path) - elif args.type == "cross-arch": + ensure_zig_path() + + if args.type in ("gdb", "cross-arch"): make_binaries(test_dir_path) else: raise NotImplementedError(args.type)