QEMU/Debugging with QEMU

From Wikibooks, open books for an open world
Jump to navigation Jump to search

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[edit | edit source]

Preventing the CPU from starting[edit | edit source]

Starting 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[edit | edit source]

The -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[edit | edit source]

It 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).