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
pull/2940/head
OBarronCS 7 months ago committed by GitHub
parent afc2c83342
commit 9539d50d49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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

@ -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}",

@ -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)

@ -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 <my_function>\n"
" ► 0x1010120 <_start> bl my_function <my_function>\n"
" x0: 0\n"
" x1: 0\n"
" x2: 0\n"
" x3: 0\n"
" \n"
" 0x10000004 <_start+4> b end <end>\n"
" 0x1010124 <_start+4> b end <end>\n"
"\n"
" 0x1000000c <end> mov x0, #0 X0 => 0\n"
" 0x10000010 <end+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x10000014 <end+8> 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 <end> mov x0, #0 X0 => 0\n"
" 0x1010130 <end+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x1010134 <end+8> svc #0\n"
" 0x1010138 <end+12> nop \n"
" 0x101013c <end+16> nop \n"
" 0x1010140 <end+20> nop \n"
" 0x1010144 <end+24> nop \n"
" 0x1010148 <end+28> nop \n"
" 0x101014c <end+32> 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 <SYS_exit>\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 <SYS_exit>\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 <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 <A>\n"
"\n"
" 0x10000010 <A> ✔ cbnz x2, B <B>\n"
" 0x1010130 <A> ✔ cbnz x2, B <B>\n"
"\n"
" 0x10000018 <B> ✔ tbz w2, #0, C <C>\n"
" 0x1010138 <B> ✔ tbz w2, #0, C <C>\n"
"\n"
" 0x10000020 <C> ✔ tbnz w2, #3, D <D>\n"
" 0x1010140 <C> ✔ tbnz w2, #3, D <D>\n"
"\n"
" 0x10000028 <D> cmp x2, x3 0xa - 0x0 CPSR => 0x20000000 [ n z C v q pan il d a i f el:0 sp ]\n"
" 0x1000002c <D+4> b.eq E <E>\n"
" 0x1010148 <D> cmp x2, x3 0xa - 0x0 CPSR => 0x20000000 [ n z C v q pan il d a i f el:0 sp ]\n"
" 0x101014c <D+4> b.eq E <E>\n"
" \n"
" 0x10000030 <D+8> nop \n"
" 0x10000034 <E> ✔ b.ne F <F>\n"
" 0x1010150 <D+8> nop \n"
" 0x1010154 <E> ✔ b.ne F <F>\n"
"\n"
" 0x1000003c <F> mov x0, #0 X0 => 0\n"
" 0x101015c <F> 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 <stores> ldr x4, stores+56 X4, [stores+56] => 0x4010e8 (value1) ◂— 0\n"
" 0x1000002c <stores+4> strb w0, [x4] [value1] <= 0xf0\n"
" 0x10000030 <stores+8> ldr x5, stores+64 X5, [stores+64] => 0x4010e9 (value2) ◂— 0\n"
" 0x10000034 <stores+12> strh w0, [x5] [value2] <= 0xdef0\n"
" 0x10000038 <stores+16> ldr x6, stores+72 X6, [stores+72] => 0x4010eb (value4) ◂— 0\n"
" 0x1000003c <stores+20> str w0, [x6] [value4] <= 0x9abcdef0\n"
" 0x10000040 <stores+24> ldr x7, stores+80 X7, [stores+80] => 0x4010ef (value8) ◂— 0\n"
" 0x10000044 <stores+28> str x0, [x7] [value8] <= 0x123456789abcdef0\n"
" 0x10000048 <stores+32> mov x8, #0x5d X8 => 0x5d\n"
" 0x1000004c <stores+36> mov x0, #0 X0 => 0\n"
" 0x10000050 <stores+40> svc #0 <SYS_exit>\n"
" ► 0x1010180 <stores> ldr x4, stores+56 X4, [stores+56] => 0x10201d8 (value1) ◂— 0\n"
" 0x1010184 <stores+4> strb w0, [x4] [value1] <= 0xf0\n"
" 0x1010188 <stores+8> ldr x5, stores+64 X5, [stores+64] => 0x10201d9 (value2) ◂— 0\n"
" 0x101018c <stores+12> strh w0, [x5] [value2] <= 0xdef0\n"
" 0x1010190 <stores+16> ldr x6, stores+72 X6, [stores+72] => 0x10201db (value4) ◂— 0\n"
" 0x1010194 <stores+20> str w0, [x6] [value4] <= 0x9abcdef0\n"
" 0x1010198 <stores+24> ldr x7, stores+80 X7, [stores+80] => 0x10201df (value8) ◂— 0\n"
" 0x101019c <stores+28> str x0, [x7] [value8] <= 0x123456789abcdef0\n"
" 0x10101a0 <stores+32> mov x8, #0x5d X8 => 0x5d\n"
" 0x10101a4 <stores+36> mov x0, #0 X0 => 0\n"
" 0x10101a8 <stores+40> svc #0 <SYS_exit>\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 <loads> ldrb w9, [x4] W9, [value1] => 0xf0\n"
" 0x10000028 <loads+4> ldrsb w10, [x4] W10, [value1] => 0xfffffff0\n"
" 0x1000002c <loads+8> ldrh w12, [x5] W12, [value2] => 0xdef0\n"
" 0x10000030 <loads+12> ldrsh w13, [x5] W13, [value2] => 0xffffdef0\n"
" 0x10000034 <loads+16> ldr w15, [x6] W15, [value4] => 0x9abcdef0\n"
" 0x10000038 <loads+20> ldrsw x16, [x6] X16, [value4] => 0xffffffff9abcdef0\n"
" 0x1000003c <loads+24> ldr x18, [x6] X18, [value4] => 0x9abcdef09abcdef0\n"
" 0x10000040 <loads+28> mov x8, #0x5d X8 => 0x5d\n"
" 0x10000044 <loads+32> mov x0, #0 X0 => 0\n"
" 0x10000048 <loads+36> svc #0 <SYS_exit>\n"
" 0x1000004c <loads+40> udf #0\n"
" ► 0x101017c <loads> ldrb w9, [x4] W9, [value1] => 0xf0\n"
" 0x1010180 <loads+4> ldrsb w10, [x4] W10, [value1] => 0xfffffff0\n"
" 0x1010184 <loads+8> ldrh w12, [x5] W12, [value2] => 0xdef0\n"
" 0x1010188 <loads+12> ldrsh w13, [x5] W13, [value2] => 0xffffdef0\n"
" 0x101018c <loads+16> ldr w15, [x6] W15, [value4] => 0x9abcdef0\n"
" 0x1010190 <loads+20> ldrsw x16, [x6] X16, [value4] => 0xffffffff9abcdef0\n"
" 0x1010194 <loads+24> ldr x18, [x6] X18, [value4] => 0x9abcdef09abcdef0\n"
" 0x1010198 <loads+28> mov x8, #0x5d X8 => 0x5d\n"
" 0x101019c <loads+32> mov x0, #0 X0 => 0\n"
" 0x10101a0 <loads+36> svc #0 <SYS_exit>\n"
" 0x10101a4 <loads+40> 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 <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 <exit>\n"
"\n"
" 0x10000020 <exit> mov x0, #0 X0 => 0\n"
" 0x10000024 <exit+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x10000028 <exit+8> svc #0 <SYS_exit>\n"
" 0x1000002c udf #0\n"
" 0x10000030 udf #0\n"
" 0x10000034 udf #0\n"
" 0x10000038 udf #0\n"
" 0x1000003c udf #0\n"
" 0x1010140 <exit> mov x0, #0 X0 => 0\n"
" 0x1010144 <exit+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x1010148 <exit+8> svc #0 <SYS_exit>\n"
" 0x101014c <exit+12> nop \n"
" 0x1010150 <exit+16> nop \n"
" 0x1010154 <exit+20> nop \n"
" 0x1010158 <exit+24> nop \n"
" 0x101015c <exit+28> 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 <exit> mov x0, #0 X0 => 0\n"
" 0x10000024 <exit+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x10000028 <exit+8> svc #0 <SYS_exit>\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 <exit> mov x0, #0 X0 => 0\n"
" 0x101017c <exit+4> mov x8, #0x5d X8 => 0x5d\n"
" 0x1010180 <exit+8> svc #0 <SYS_exit>\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)

@ -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 <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 <not_equal>\n"
"\n"
" 0x10000018 <not_equal> mov r3, #1 R3 => 1\n"
" 0x1000001c <not_equal+4> cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n"
" 0x10000020 <not_equal+8> ✔ bgt greater <greater>\n"
" 0x200cc <not_equal> mov r3, #1 R3 => 1\n"
" 0x200d0 <not_equal+4> cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n"
" 0x200d4 <not_equal+8> ✔ bgt greater <greater>\n"
"\n"
" 0x1000002c <greater> cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n"
" 0x10000030 <greater+4> ✔ bls end <end>\n"
" 0x200e0 <greater> cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n"
" 0x200e4 <greater+4> ✔ bls end <end>\n"
"\n"
" 0x1000003c <end> mov r0, #0 R0 => 0\n"
" 0x10000040 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200f0 <end> mov r0, #0 R0 => 0\n"
" 0x200f4 <end+4> 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 <not_equal>\n"
" 0x200c0 <_start+12> ✔ bne not_equal <not_equal>\n"
"\n"
" 0x10000018 <not_equal> mov r3, #1 R3 => 1\n"
" 0x1000001c <not_equal+4> cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n"
" 0x10000020 <not_equal+8> ✔ bgt greater <greater>\n"
" 0x200cc <not_equal> mov r3, #1 R3 => 1\n"
" 0x200d0 <not_equal+4> cmp r1, r3 0xa - 0x1 CPSR => 0x20000010 [ n z C v q j t e a i f ]\n"
" 0x200d4 <not_equal+8> ✔ bgt greater <greater>\n"
"\n"
" 0x1000002c <greater> cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n"
" ► 0x10000030 <greater+4> ✔ bls end <end>\n"
" 0x200e0 <greater> cmp r3, r1 0x1 - 0xa CPSR => 0x80000010 [ N z c v q j t e a i f ]\n"
" ► 0x200e4 <greater+4> ✔ bls end <end>\n"
"\n"
" 0x1000003c <end> mov r0, #0 R0 => 0\n"
" 0x10000040 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000044 <end+8> svc #0 <SYS_exit_group>\n"
" 0x10000048 andeq r1, r0, r1, asr #24\n"
" 0x200f0 <end> mov r0, #0 R0 => 0\n"
" 0x200f4 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200f8 <end+8> svc #0 <SYS_exit_group>\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 <end> mov.w r0, #0 R0 => 0\n"
" 0x10000012 <end+4> mov.w r7, #0xf8 R7 => 0xf8\n"
" 0x10000016 <end+8> svc #0 <SYS_exit_group>\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 <end> mov.w r0, #0 R0 => 0\n"
" 0x200c6 <end+4> mov.w r7, #0xf8 R7 => 0xf8\n"
" 0x200ca <end+8> svc #0 <SYS_exit_group>\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 <end> mov.w r0, #0 R0 => 0\n"
" 0x10000012 <end+4> mov.w r7, #0xf8 R7 => 0xf8\n"
" 0x10000016 <end+8> svc #0 <SYS_exit_group>\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 <end> mov.w r0, #0 R0 => 0\n"
" 0x200c6 <end+4> mov.w r7, #0xf8 R7 => 0xf8\n"
" 0x200ca <end+8> svc #0 <SYS_exit_group>\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] <end>\n"
" ► 0x200b4 <_start> ldr pc, [pc, #0xc] <end>\n"
"\n"
" 0x10000008 <end> mov r0, #0 R0 => 0\n"
" 0x1000000c <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000010 <end+8> svc #0 <SYS_exit_group>\n"
" 0x10000014 <end+12> andne r0, r0, r8\n"
" 0x10000018 andeq r1, r0, r1, asr #24\n"
" 0x200bc <end> mov r0, #0 R0 => 0\n"
" 0x200c0 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200c4 <end+8> svc #0 <SYS_exit_group>\n"
" 0x200c8 <end+12> 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] <end>\n"
" 0x200b4 <_start> ldr pc, [pc, #0xc] <end>\n"
"\n"
" ► 0x10000008 <end> mov r0, #0 R0 => 0\n"
" 0x1000000c <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000010 <end+8> svc #0 <SYS_exit_group>\n"
" 0x10000014 <end+12> andne r0, r0, r8\n"
" 0x10000018 andeq r1, r0, r1, asr #24\n"
" ► 0x200bc <end> mov r0, #0 R0 => 0\n"
" 0x200c0 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200c4 <end+8> svc #0 <SYS_exit_group>\n"
" 0x200c8 <end+12> 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 <end> mov r0, #0 R0 => 0\n"
" 0x10000024 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000028 <end+8> svc #0 <SYS_exit_group>\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 <end> mov r0, #0 R0 => 0\n"
" 0x200d8 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200dc <end+8> svc #0 <SYS_exit_group>\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 <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 <end>\n"
"\n"
" 0x1000001c <end> mov r0, #0 R0 => 0\n"
" 0x10000020 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000024 <end+8> svc #0 <SYS_exit_group>\n"
" 0x10000028 andeq r1, r0, r1, asr #24\n"
" 0x200d0 <end> mov r0, #0 R0 => 0\n"
" 0x200d4 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200d8 <end+8> svc #0 <SYS_exit_group>\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 <func>\n"
" ► 0x200b4 <_start> nop \n"
" 0x200b8 <_start+4> bl func <func>\n"
" \n"
" 0x10000008 <_start+8> nop \n"
" 0x1000000c <_start+12> nop \n"
" 0x10000010 <end> mov r0, #0 R0 => 0\n"
" 0x10000014 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x10000018 <end+8> svc #0\n"
" 0x1000001c <end+12> nop \n"
" 0x10000020 <end+16> nop \n"
" 0x10000024 <end+20> nop \n"
" 0x10000028 <end+24> nop \n"
" 0x200bc <_start+8> nop \n"
" 0x200c0 <_start+12> nop \n"
" 0x200c4 <end> mov r0, #0 R0 => 0\n"
" 0x200c8 <end+4> mov r7, #0xf8 R7 => 0xf8\n"
" 0x200cc <end+8> svc #0\n"
" 0x200d0 <end+12> nop \n"
" 0x200d4 <end+16> nop \n"
" 0x200d8 <end+20> nop \n"
" 0x200dc <end+24> 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"
)

@ -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")

@ -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 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x10000014 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x10000018 <end+8> syscall \n"
" 0x2015c <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n"
" 0x20160 <_target+4> nop \n"
" 0x20164 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x20168 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x2016c <end+8> 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 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x10000014 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x10000018 <end+8> syscall \n"
" ► 0x2015c <_target> addu $gp, $gp, $ra GP => 0 (0 + 0)\n"
" 0x20160 <_target+4> nop \n"
" 0x20164 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x20168 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x2016c <end+8> 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 <end>\n"
" 0x10000008 <_start+8> nop \n"
" ► 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n"
" 0x20154 <__start+4> ✔ bnez $t0, end <end>\n"
" 0x20158 <__start+8> nop \n"
"\n"
" 0x10000014 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x10000018 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x1000001c <end+8> syscall \n"
" 0x20168 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x2016c <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x20170 <end+8> 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 <end>\n"
" 0x10000008 <_start+8> nop \n"
" ► 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n"
" 0x20154 <__start+4> bnez $t0, end <end>\n"
" 0x20158 <__start+8> nop \n"
" \n"
" 0x1000000c <_start+12> nop \n"
" 0x10000010 <_start+16> nop \n"
" 0x10000014 <end> addiu $v0, $zero, 0xfa1\n"
" 0x10000018 <end+4> addiu $a0, $zero, 0\n"
" 0x1000001c <end+8> syscall \n"
"\n"
" 0x2015c <__start+12> nop \n"
" 0x20160 <__start+16> nop \n"
" 0x20164 <__start+20> nop \n"
" 0x20168 <end> addiu $v0, $zero, 0xfa1\n"
" 0x2016c <end+4> addiu $a0, $zero, 0\n"
" 0x20170 <end+8> 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 <end>\n"
" 0x10000008 <_start+8> nop \n"
" 0x20150 <__start> addiu $t0, $zero, 0xa T0 => 0x0 + 0xa\n"
" ► 0x20154 <__start+4> ✔ bnez $t0, end <end>\n"
" 0x20158 <__start+8> nop \n"
"\n"
" 0x10000014 <end> addiu $v0, $zero, 0xfa1\n"
" 0x10000018 <end+4> addiu $a0, $zero, 0\n"
" 0x1000001c <end+8> syscall \n"
" 0x20168 <end> addiu $v0, $zero, 0xfa1\n"
" 0x2016c <end+4> addiu $a0, $zero, 0\n"
" 0x20170 <end+8> 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 <my_function>\n"
" ► 0x20150 <__start> jal my_function <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 <end>\n"
" 0x1000000c <_start+12> nop \n"
" 0x20158 <__start+8> nop \n"
" 0x2015c <__start+12> j end <end>\n"
" 0x20160 <__start+16> nop \n"
"\n"
" 0x10000014 <end> addiu $v0, $zero, 0xfa1\n"
" 0x10000018 <end+4> addiu $a0, $zero, 0\n"
" 0x1000001c <end+8> syscall \n"
" 0x20170 <end> addiu $v0, $zero, 0xfa1\n"
" 0x20174 <end+4> addiu $a0, $zero, 0\n"
" 0x20178 <end+8> 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 <my_function>\n"
" 0x10000004 <_start+4> nop \n"
" 0x20150 <__start> jal my_function <my_function>\n"
" 0x20154 <__start+4> nop \n"
" \n"
" 0x10000008 <_start+8> j end <end>\n"
" 0x1000000c <_start+12> nop \n"
" 0x20158 <__start+8> nop \n"
" 0x2015c <__start+12> j end <end>\n"
" 0x20160 <__start+16> nop \n"
"\n"
" ► 0x10000014 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x10000018 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x1000001c <end+8> syscall \n"
"\n"
" ► 0x20170 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x20174 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x20178 <end+8> 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 <loads> lw $t1, 0($s0) T1, [value1] => 0xffffffff\n"
" 0x1000003c <loads+4> lhu $t2, 0($s1) T2, [value2] => 0xffff\n"
" 0x10000040 <loads+8> lbu $t3, 0($s2) T3, [value3] => 0xff\n"
" 0x10000044 <loads+12> lw $t4, 0($s0) T4, [value1] => 0xffffffff\n"
" 0x10000048 <loads+16> lh $t5, 0($s1) T5, [value2] => 0xffffffff\n"
" 0x1000004c <loads+20> lb $t6, 0($s2) T6, [value3] => 0xffffffff\n"
" ► 0x20188 <loads> lw $t1, 0($s0) T1, [value1] => 0xffffffff\n"
" 0x2018c <loads+4> lhu $t2, 0($s1) T2, [value2] => 0xffff\n"
" 0x20190 <loads+8> lbu $t3, 0($s2) T3, [value3] => 0xff\n"
" 0x20194 <loads+12> lw $t4, 0($s0) T4, [value1] => 0xffffffff\n"
" 0x20198 <loads+16> lh $t5, 0($s1) T5, [value2] => 0xffffffff\n"
" 0x2019c <loads+20> 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 <first>\n"
" 0x10000008 <_start+8> nop \n"
" ► 0x20150 <__start> nop \n"
" 0x20154 <__start+4> ✔ beq $t1, $t0, first <first>\n"
" 0x20158 <__start+8> nop \n"
"\n"
" 0x10000010 <first> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n"
" 0x10000014 <first+4> ✔ bnez $t0, second <second>\n"
" 0x10000018 <first+8> nop \n"
" 0x20164 <first> addiu $t0, $zero, 0xa T0 => 10 (0x0 + 0xa)\n"
" 0x20168 <first+4> ✔ bnez $t0, second <second>\n"
" 0x2016c <first+8> nop \n"
"\n"
" 0x10000020 <second> b end <end>\n"
" 0x10000024 <second+4> nop \n"
" 0x20178 <second> b end <end>\n"
" 0x2017c <second+4> nop \n"
"\n"
" 0x1000002c <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x10000030 <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x10000034 <end+8> syscall \n"
" 0x20188 <end> addiu $v0, $zero, 0xfa1 V0 => 0xfa1 (0x0 + 0xfa1)\n"
" 0x2018c <end+4> addiu $a0, $zero, 0 A0 => 0 (0 + 0)\n"
" 0x20190 <end+8> syscall \n"
"────────────────────────────────────────────────────────────────────────────────\n"
)

@ -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 <function>\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 <function>\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 <store> c.sd a0, 0(a2) [data] <= 0x1234567890abcdef\n"
" 0x1000002a <store+2> c.ld a1, 0(a2) A1, [data] => 0x1234567890abcdef\n"
" 0x1000002c <store+4> c.li a1, 0x10 A1 => 0x10\n"
" 0x1000002e <store+6> addi a2, zero, 0x26 A2 => 38 (0x0 + 0x26)\n"
" 0x10000032 <store+10> add a4, a1, a2 A4 => 54 (0x10 + 0x26)\n"
" 0x10000036 <store+14> sub a5, a1, a3 A5 => 16 (0x10 - 0x0)\n"
" 0x1000003a <store+18> xor a6, a1, a2 A6 => 54 (0x10 ^ 0x26)\n"
" 0x1000003e <store+22> and a7, a1, a2 A7 => 0 (0x10 & 0x26)\n"
" 0x10000042 <store+26> sll a3, a1, a2 A3 => 0x40000000000 (0x10 << 0x26)\n"
" 0x10000046 <store+30> mul a2, a1, a2 A2 => 0x260 (0x10 * 0x26)\n"
" 0x1000004a <store+34> div a5, a3, a2 A5 => 0x1af286bca (0x40000000000 / 0x260)\n"
" ► 0x10011b8 <store> c.sd a0, 0(a2) [data] <= 0x1234567890abcdef\n"
" 0x10011ba <store+2> c.ld a1, 0(a2) A1, [data] => 0x1234567890abcdef\n"
" 0x10011bc <store+4> c.li a1, 0x10 A1 => 0x10\n"
" 0x10011be <store+6> addi a2, zero, 0x26 A2 => 38 (0x0 + 0x26)\n"
" 0x10011c2 <store+10> add a4, a1, a2 A4 => 54 (0x10 + 0x26)\n"
" 0x10011c6 <store+14> sub a5, a1, a3 A5 => 16 (0x10 - 0x0)\n"
" 0x10011ca <store+18> xor a6, a1, a2 A6 => 54 (0x10 ^ 0x26)\n"
" 0x10011ce <store+22> and a7, a1, a2 A7 => 0 (0x10 & 0x26)\n"
" 0x10011d2 <store+26> sll a3, a1, a2 A3 => 0x40000000000 (0x10 << 0x26)\n"
" 0x10011d6 <store+30> mul a2, a1, a2 A2 => 0x260 (0x10 * 0x26)\n"
" 0x10011da <store+34> 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 <first>\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 <first>\n"
" \n"
" 0x10000008 <_start+8> c.nop \n"
" 0x1000000a <first> ✔ bne t0, t2, 6 <second>\n"
" 0x1001160 <_start+8> c.nop \n"
" 0x1001162 <first> ✔ bne t0, t2, 6 <second>\n"
"\n"
" 0x10000010 <second> blt t0, t3, 6 <third>\n"
" 0x1001168 <second> blt t0, t3, 6 <third>\n"
" \n"
" 0x10000014 <second+4> c.nop \n"
" 0x10000016 <third> ✔ bge t0, t4, 6 <fourth>\n"
" 0x100116c <second+4> c.nop \n"
" 0x100116e <third> ✔ bge t0, t4, 6 <fourth>\n"
"\n"
" 0x1000001c <fourth> ✔ blt t5, t0, 6 <end>\n"
" 0x1001174 <fourth> ✔ blt t5, t0, 6 <end>\n"
"\n"
" 0x10000022 <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x10000024 <end+2> addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n"
" 0x100117a <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x100117c <end+2> 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 <first>\n"
" 0x100115a <_start+2> c.li t1, 5 T1 => 5\n"
" 0x100115c <_start+4> beq t0, t1, 6 <first>\n"
" \n"
" 0x10000008 <_start+8> c.nop \n"
" 0x1000000a <first> ✔ bne t0, t2, 6 <second>\n"
" 0x1001160 <_start+8> c.nop \n"
" 0x1001162 <first> ✔ bne t0, t2, 6 <second>\n"
"\n"
" 0x10000010 <second> blt t0, t3, 6 <third>\n"
" 0x1001168 <second> blt t0, t3, 6 <third>\n"
" \n"
" ► 0x10000014 <second+4> c.nop \n"
" 0x10000016 <third> ✔ bge t0, t4, 6 <fourth>\n"
" ► 0x100116c <second+4> c.nop \n"
" 0x100116e <third> ✔ bge t0, t4, 6 <fourth>\n"
"\n"
" 0x1000001c <fourth> ✔ blt t5, t0, 6 <end>\n"
" 0x1001174 <fourth> ✔ blt t5, t0, 6 <end>\n"
"\n"
" 0x10000022 <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x10000024 <end+2> addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n"
" 0x10000028 <end+6> c.li a0, 0 A0 => 0\n"
" 0x100117a <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x100117c <end+2> addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n"
" 0x1001180 <end+6> 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 <a>\n"
" ► 0x1001158 <_start> c.j 2 <a>\n"
"\n"
" 0x10000002 <a> c.j 2 <b>\n"
" 0x100115a <a> c.j 2 <b>\n"
"\n"
" 0x10000004 <b> c.j 2 <c>\n"
" 0x100115c <b> c.j 2 <c>\n"
"\n"
" 0x10000006 <c> c.j 2 <d>\n"
" 0x100115e <c> c.j 2 <d>\n"
"\n"
" 0x10000008 <d> c.j 2 <e>\n"
" 0x1001160 <d> c.j 2 <e>\n"
"\n"
" 0x1000000a <e> c.j 2 <end>\n"
" 0x1001162 <e> c.j 2 <end>\n"
"\n"
" 0x1000000c <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x1000000e <end+2> addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n"
" 0x10000012 <end+6> c.li a0, 0 A0 => 0\n"
" 0x10000014 <end+8> ecall <SYS_exit>\n"
" 0x10000018 c.addiw s6, -0x10\n"
" 0x1001164 <end> c.li a2, 0x1e A2 => 0x1e\n"
" 0x1001166 <end+2> addi a7, zero, 0x5d A7 => 93 (0x0 + 0x5d)\n"
" 0x100116a <end+6> c.li a0, 0 A0 => 0\n"
" 0x100116c <end+8> ecall <SYS_exit>\n"
" 0x1001170 c.addiw s6, -0x10\n"
"────────────────────────────────────────────────────────────────────────────────\n"
)

@ -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)

Loading…
Cancel
Save