Qemu Debug
Timeline
2025-11-23
- init
Environment
1 | wget https://download.qemu.org/qemu-10.1.2.tar.xz |
Create .clangd:
1 | CompileFlags: |
Source-Level Debugging
Unlike debugging a kernel (which requires starting first, then attaching via gdb), QEMU can be debugged directly since it runs natively on the host. (Make sure to compile with --enable-debug.)
gdb
Direct gdb debugging:
1 | $ gdb --args ./build/riscv64-softmmu/qemu-system-riscv64 \ |
VSCode
.vscode/launch.json
1 | { |
Remote Debugging
QEMU has a built-in gdbserver for controlling the guest processor. Any gdb client can connect.
1 | $QEMU $QEMU_ARGS -s -S |
-s: Start gdbstub on port 1234.-S: Halt QEMU at the guest’s first instruction, waiting for a gdb client.
To specify a custom port:
1 | $QEMU $QEMU_ARGS -gdb tcp::<your-port> -S |
Connect with the appropriate architecture’s gdb:
1 | $ARCH-gdb $BINARY -ex "target remote localhost:1234" |
Log Debugging
QEMU has a flexible logging system for observing guest state (instruction flow, interrupts, exceptions, syscalls).
1 | $QEMU $QEMU_ARGS -d <log-type,...> -D <log-file-name> |
-d: Specify log types (comma-separated).-D: Specify output file path (default: stdout).
View supported log types:
1 | $QEMU -d ? |
Common combinations:
- Observe TCG instruction translation:
1 | $QEMU $QEMU_ARGS -d in_asm,op,out_asm -D tcg.log |
- Observe CPU state (registers, interrupts/exceptions):
1 | $QEMU $QEMU_ARGS -d exec,cpu,int -D cpu.log |
- Precise instruction trace (one instruction per TB):
1 | $QEMU $QEMU_ARGS --accel tcg,one-insn-per-tb=on -d exec,cpu,int -D cpu.log |
Trace Events
Reference:
QEMU has a powerful tracing tool for tracking internal function execution and performance tuning.
Quick Start
Trace memory region access events:
1 | $ qemu-system-riscv64 -M virt --trace "memory_region_ops_*" |
Multiple trace events and file output:
1 | echo "memory_region_ops_*" >/tmp/events |
Dynamic enabling via QEMU monitor:
1 | $ qemu-system-riscv64 -M virt -monitor stdio -S -display none |
Use info trace-events to list supported events.
Adding New Trace Events
Two steps:
- Declare the trace-event in the corresponding directory’s trace-events file.
- Add the event function call in the target source code.
Example format:
1 | qemu_vmalloc(size_t size, void *ptr) "size %zu ptr %p" |
Each event declaration starts with the event name, followed by parameters, and a format string for pretty-printing.
Usage in source:
1 |
|
Trace Backends
QEMU tracing uses a frontend/backend separation design, supporting multiple backends: log, simple, ftrace, dtrace.
Enable specific backends:
1 | ./configure --enable-trace-backends=simple,dtrace |
The simple backend writes binary trace logs to a file via a separate thread, with lower overhead than the log backend.
Analyzing Trace Files
Format with simpletrace.py:
1 | ./scripts/simpletrace.py <trace-events-all> <trace-log> |
Ensure the trace-events-all file matches the one generated when QEMU was built.
Reference:
