Kernel debugging QEMU

Debugging the FreeBSD kernel in QEMU is really straight forward. Get yourself some kernel symbols (either from the build dir or for /usr/lib/debug/kernel* ), load them into gdb, kick of QEMU with -s -S and connect.

$ qemu-system-x86_64 ... -s -S ...

The -S flag causes QEMU to wait for the gdbstub to start execution rather than letting CPUs free immediately. So we need to connect with gdb to get going.

$ gdb kernel.debug
(gdb) target remote localhost:1234
(gbd) c

Usage is documented a little in the manual (as much as anything is ever gdb documented).

I got the steps from a FreeBSD 10 guide and other than the symbols file changing in between everything is about the same. It is nice when things don't change.

gdb is nice and all, but can we use a debugger that ships with FreeBSD?

The lldb documentation suggests that we can do something like this:

(lldb) platform list
Available platforms:
host: Local FreeBSD user platform plug-in.
remote-freebsd: Remote FreeBSD user platform plug-in.
remote-gdb-server: A platform that uses the GDB remote protocol as the communication transport.
qemu-user: Platform for debugging binaries under user mode qemu
(lldb) platform select remote-gdb-server
  Platform: remote-gdb-server
 Connected: no
(lldb) platform connect connect://localhost:1234
  Platform: remote-gdb-server
  Hostname: (null)
 Connected: yes

It will say everything is connected, but when we try to continue we get an error.

 (lldb) c
error: invalid target, create a target using the 'target create' command

From a stackoverflow question I found the gdb-remote command which does what the documentation don't:

(lldb) gdb-remote localhost:1234
Process 1 stopped
* thread #1, stop reason = signal SIGTRAP
    frame #0: 0x000000000000fff0
->  0xfff0: addb   %al, (%rax)
    0xfff2: addb   %al, (%rax)
    0xfff4: addb   %al, (%rax)
    0xfff6: addb   %al, (%rax)
(lldb) c
Process 1 resuming
Process 1 stopped
* thread #4, stop reason = signal SIGINT
    frame #0: 0xffffffff805ee459
->  0xffffffff805ee459: incl   %eax
    0xffffffff805ee45b: cmpl   0x812097(%rip), %eax
    0xffffffff805ee461: jl     0xffffffff805ee450
    0xffffffff805ee463: nopw   %cs:(%rax,%rax)
(lldb) list udp_output
error: Could not find function named: "udp_output"

Things are confused.

(lldb) image list
[  0] 7A0DEA14 0x0000000000200000 /sbin/init

(lldb) f
error: Command requires a process which is currently stopped.
(lldb) c
error: Process is running.  Use 'process interrupt' to pause execution.

Out of the box like this I think lldb needs some more configuration. Frustratingly as always the documentation around debugging is seriously lacking.

gdb isn't perfect either:

End of the file was already reached, use "list ." to list the current location again
(gdb) list .

Fatal signal: Segmentation fault
----- Backtrace -----
0x1350771 ???
0x14717f6 ???
0x1471f7f ???
0x82fbf457f handle_signal
0x82fbf3b3a thr_sighandler
0x8230ef2d2 ???
0x173da31 ???
0x137ac37 ???
0x1384a35 ???
0x17cb202 ???
0x1470faa ???
0x1471335 ???
0x14709a2 ???
0x8262127c2 ???
0x1471d8d ???
0x14705fc ???
0x17ff86f ???
0x1cab092 ???
0x1caab64 ???
0x1576a59 ???
0x1573c40 ???
0x1250760 ???
0x83000d839 __libc_start1
0x125064f ???
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:

zsh: segmentation fault (core dumped)  gdb

a links post?