Debugging a kernel can be challenging. Sometimes a straightforward
approach to debugging works: you can add log_printf()
statements
to the kernel, or console_printf()
statements to user-level code,
to print state and see how it evolves. Unfortunately, sometimes these
techniques don’t work. For example, your kernel might be so messed
up during early boot that the kernel cannot properly initialize
the console used by log_printf()
. In this scenario, you might at
least be able to see whether the kernel is reaching a certain point by
intentionally inserting an infinite loop into your kernel code—if
your kernel hangs, the line of code representing the infinite loop
was reached, but if your kernel crashes, the line was not reached.
However, debug print statements or the infinite looping trick cannot be used in all cases. For example, debugging deadlocks or synchronization errors is difficult in part because print statements or slow loops can change the order in which concurrent pieces of code execute; perturbing the order may result in the concurrency bug disappearing! [Or really, the bug is still there, but the manifestation has gone away.]
In these situations, debugging Chickadee with gdb
might be helpful.
For example, suppose that you want to debug Chickadee as it runs
p-testzombie.cc
. From a terminal window in your Linux VM, do
make run-gdb-testzombie
; this will compile Chickadee and launch
qemu
as well as gdb
. The qemu
window will initially be paused.
In your terminal window, you’ll see the gdb
command line. From
that command line, you can set breakpoints in both Chickadee code
and user-level code like p-testzombie.cc
. For example, you can set
a breakpoint in p-testzombie.cc
by typing break p-testzombie.cc:SOME_LINE_NUMBER
into the gdb
command line. Then, if you type continue
, this will
tell gdb
to allow qemu
to proceed with executing Chickadee.
Later, when one of your breakpoints is hit, control will return to
gdb
. At this point, you can then type things like print SOME_VAR_NAME
to see the value for a C++-level variable. You can also do info registers
to print all of the register values. If you only want to print one
register value, you can do something like print $rsp
to just print %rsp
.
gdb
is very powerful. A variety of tutorials on the Internet discuss
how to use gdb
. For example, see this page for an
overview of the most useful gdb
commands.