QEMU/Debugging with QEMU
QEMU offers a comfortable way to do system-wide debugging; this environment is specially suited to debug operating system kernels and firmware.
You can actually connect any debugger supporting the GDB remote protocol. For the following examples however, we will be using the GNU Debugger.
Starting a debugging session
editPreventing the CPU from starting
editStarting QEMU with the -S
command-line switch prevents the CPU from starting. This gives time for the debugger to connect and allows to start debugging from the very beginning, even the early platform firmware.
To start execution, you must send QEMU the "continue" command, either via the debugger or the monitor console.
Connecting to the Debugger
editThe -gdb {device}
command-line switch allows you to specify QEMU to wait for a connection in the specified device.
It can accept serial, socket, udp, tcp, stdio
, etc. E.g. -gdb tcp::9000
to listen on port 9000, then from GDB you can connect to it with target remote localhost:9000
.
The -s
switch is a shorthand for -gdb tcp::1234
.
Launching QEMU from GDB
editIt is possible to launch QEMU from within GDB; you can conveniently save the desired commands to a file and have GDB load the script.
For example, lets suppose you have a very simple custom MBR that loads a kernel in protected mode at 0x7E00, you can debug both with something like:
add-symbol-file stage0.elf 0x7c00
add-symbol-file stage1.elf 0x7e00
target remote | qemu -S -gdb stdio -m 16 -boot c -hda drive0.img
Then you can start it like this: gdb -x script.gdb
More complex setups, taking into account run-time relocations are possible by scripting and setting breakpoints. This is common when debugging bootstrapping code that relocates itself before loading the next stage (e.g. standard MBR).