QEMU Debugging
About 1103 wordsAbout 4 min
2026-03-14
This page covers QEMU's internal debug mechanisms: the -d flag log categories, the Monitor command reference, the qemu-system-arm -d help output decoded, and how to debug QEMU itself as a C program.
This is distinct from the GDB-based guest debugging covered in QEMU GDB Debugging. Here the subject is QEMU's own instrumentation for observing emulation internals.
The -d Flag
-d activates QEMU's internal debug log. Output goes to stderr by default, or to a file with -D <path>.
qemu-system-arm -M mps2-an385 -kernel firmware.elf -nographic \
-d in_asm,int -D /tmp/qemu-debug.logFull Flag Reference
qemu-system-arm -d help| Flag | Description |
|---|---|
in_asm | Guest assembly instructions as decoded from the binary |
out_asm | Host assembly instructions generated by TCG |
op | TCG intermediate ops before optimization |
op_opt | TCG intermediate ops after optimization (final form) |
op_ind | TCG ops with instruction indirection info |
int | Hardware interrupts and CPU exceptions (ARM: IRQ, FIQ, SVC, prefetch abort, etc.) |
exec | Every translation block executed (very verbose, slows execution ~10x) |
cpu | CPU register state dump before each TB execution |
cpu_reset | CPU register dump at every reset event |
mmu | TLB misses and refills (softmmu page table walks) |
pcall | x86 protected-mode far calls and task switches |
cpu_io | CPU-level I/O port accesses (x86 IN/OUT instructions) |
nochain | Disable TB chaining; every TB ends with a return to the dispatcher |
page | Page table updates |
strace | Linux system call trace (qemu-user mode only) |
unimp | Guest accesses to unimplemented registers or features |
guest_errors | Guest-level errors: misaligned accesses, undefined instructions |
trace:* | Enable trace events matching a pattern (see Tracing page) |
Multiple flags are comma-separated: -d in_asm,op_opt,int
Reading in_asm Output
in_asm shows guest code as QEMU decodes it for translation:
----------------
IN: Reset_Handler
0x00000008: e59f0010 ldr r0, [pc, #16] ; load _sidata
0x0000000c: e59f1010 ldr r1, [pc, #16] ; load _sdata
0x00000010: e59f2010 ldr r2, [pc, #16] ; load _edataThe format is: <physical address>: <hex encoding> <disassembly>
The TB boundary is shown by the IN: header. Each new IN: starts a new translation block (e.g., after a branch or interrupt).
Reading out_asm Output
out_asm shows the x86_64 (or host architecture) code TCG generated:
OUT: [size=108]
0x7f3c4a000000: push %rbp
0x7f3c4a000001: mov %rsp,%rbp
0x7f3c4a000010: mov 0x18(%rbx),%eax ; load ARM r0
0x7f3c4a000014: mov 0x50(%rbx),%ecx ; load ARM pc
0x7f3c4a000018: add $0x10,%ecx ; pc + 16
0x7f3c4a00001c: mov (%rcx),%eax ; LDR r0, [pc, #16]%rbx is QEMU's CPU state pointer (CPUARMState *). Register accesses are struct field loads/stores.
Reading int Output
int logs exception entry and exit:
IRQ 5 raised ; NVIC asserts IRQ5 (e.g., UART0)
Entering exception 21 ; IRQ5 = exception number 5+16=21
...
Returning from exception 21For debugging interrupt handling in firmware, -d int is invaluable. Common ARM abort types visible in this log:
| Exception name | Exception number | Likely cause |
|---|---|---|
| Reset | 1 | Watchdog, manual reset |
| HardFault | 3 | Unhandled fault escalation |
| MemManage | 4 | MPU violation |
| BusFault | 5 | Bad memory address |
| UsageFault | 6 | Undefined instruction, divide-by-zero |
| SVC | 11 | Software interrupt (RTOS syscall) |
| PendSV | 14 | Context switch (RTOS) |
| SysTick | 15 | Timer tick |
| IRQ0–239 | 16–255 | Peripheral interrupts |
Reading mmu Output
mmu logs TLB fills and page table walks (relevant for Linux guests, not bare-metal):
TLB fill: vaddr=0xc0008000 paddr=0x80008000 prot=rwxUseful for diagnosing page mapping issues or debugging early boot where the MMU is enabled/disabled.
Reading unimp and guest_errors
-d unimp,guest_errorsunimp fires when guest code accesses a register QEMU hasn't implemented:
hw/arm/mps2-an385: unimplemented read of register at offset 0x500guest_errors fires on architectural errors:
Guest ARM: Undefined instruction 0xe7f001f0 at pc=0x00000234These are critical for discovering which peripherals your firmware uses that QEMU doesn't model.
-D <logfile>: Redirecting Debug Output
By default -d output goes to stderr, which is mixed with serial console output in -nographic mode. Always redirect:
-D /tmp/qemu-debug.log -d in_asm,int,unimpThen in another terminal:
tail -f /tmp/qemu-debug.logQEMU Monitor Reference
The Monitor is an interactive console for controlling the running VM. Access via:
Ctrl-A C(when using-nographicor-serial mon:stdio)-monitor stdio(dedicate stdio to monitor)-monitor unix:/tmp/mon.sock,server,nowait(Unix socket)
Execution Control
stop # pause all vCPUs
cont # resume
quit # exit QEMU
system_reset # hardware reset
system_powerdown # ACPI shutdown signalCPU Inspection
info registers # all CPU registers (current vCPU)
info registers -a # all vCPUs
info cpus # list vCPUs and their stateMemory Inspection
x /N[fmt][size] <addr> # virtual memory examine
xp /N[fmt][size] <addr> # physical memory examine
# Formats: x=hex, d=decimal, u=unsigned, o=octal, s=string, i=instructions
# Sizes: b=1, h=2, w=4, g=8
# Examples:
x /8xw 0x20000000 # 8 hex words from SRAM start
x /16i $pc # 16 instructions from PC (requires ELF symbols loaded)
xp /4xg 0x00000000 # 4 quadwords at physical address 0
p <expr> # evaluate expression
p $r0 # print ARM register r0
p 0x40004000 # print address valueDevice and Memory Map Inspection
info mtree # memory region tree (full address space layout)
info qtree # QOM device tree
info block # block devices
info network # network interfaces
info chardev # character devices
info usb # USB devices
info pcie # PCIe devices
info snapshots # saved VM snapshotsBlock and Snapshots
drive_add 0 file=disk2.qcow2,format=qcow2,if=none,id=hd1
device_add virtio-blk-pci,drive=hd1 # hot-plug
device_del virtio-blk-pci-0 # hot-remove
savevm <tag> # save snapshot
loadvm <tag> # restore snapshot
delvm <tag> # delete snapshot
migrate file:/tmp/vm.state # save full state to fileDebugging QEMU Source Itself
For contributors diagnosing QEMU bugs or developing device models:
Build with Debug Symbols
cd qemu-build
../qemu/configure --target-list=arm-softmmu \
--enable-debug \
--disable-strip \
--extra-cflags="-O0 -g3"
ninja -j$(nproc)--enable-debug adds -g and disables some optimizations. -O0 (via extra flags) further improves GDB stepping quality at the cost of QEMU performance.
GDB on QEMU Itself
gdb --args ./arm-softmmu/qemu-system-arm \
-M mps2-an385 -kernel firmware.elf -nographic
(gdb) b pl011_write # break in PL011 TX
(gdb) b memory_region_dispatch_write # break on any MMIO write
(gdb) runUseful breakpoint locations for device model debugging:
| Function | Purpose |
|---|---|
memory_region_dispatch_write | Any guest MMIO write |
memory_region_dispatch_read | Any guest MMIO read |
cpu_exec | Before each TB execution |
tb_gen_code | TCG translates a new TB |
arm_cpu_do_interrupt | ARM exception entry |
qemu_set_irq | IRQ assertion |
qemu_chr_fe_write_all | Chardev output |
AddressSanitizer
Build QEMU with ASAN to catch memory bugs in device models:
../qemu/configure --target-list=arm-softmmu \
--enable-sanitizers
ninja -j$(nproc)ASAN will report use-after-free, buffer overflows, and use-before-initialization in QEMU's C code.