[[!meta copyright="Copyright © 2007, 2008, 2009, 2011 Free Software Foundation, Inc."]] [[!meta license="""[[!toggle id="license" text="GFDL 1.2+"]][[!toggleable id="license" text="Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled [[GNU Free Documentation License|/fdl]]."]]"""]] Here are some hints to debug with GNU Mach Mach has a built-in kernel debugger. [Manual](http://www.gnu.org/software/hurd/gnumach-doc/Kernel-Debugger.html). First, make sure to enable it. Either by using a pre-packaged gnumach-image-something-dbg, or by passing --enable-kdb to the ./configure invocation. Then, reproduce the issue again. If something like a kernel trap happens, you will end up in the GNU Mach debugger. Otherwise, type control-alt-d to make Mach enter it by hand. The debugger has an extensive documentation on http://www.gnu.org/software/hurd/gnumach-doc/Kernel-Debugger.html , but a quick start is the following. To get the register values, type show registers To get a backtrace, type trace, which will print both function return addresses and function parameters, such as 0x107cf1(8088488,5e,40000008,2aa008,0) 0x1071bc(0,0,0,0,0) 0x106831(24fe00,2000,b,800,0) Run the addr2line tool on the return addresses: addr2line -i -f -e /boot/gnumach 0x107cf1 0x1071bc 0x106831 This will print the source code lines of the backtrace. To examine the backtrace of some given thread, use show all thread/u to get the whole listing of all tasks and threads. You can then use trace/t to trace a specific thread. Unfortunately, userland and kernelland use the same range of addresses, so one can not get userland traces easily. The Xen port uses different ranges, and in that case one can use trace/u to also get the userland trace. To examine a variable, use nm /boot/gnumach to get the address of the variable (e.g. 0x123400), and use x 0x123400 to read it. One can also write to it by using w 0x123400 Another interesting feature is watching a variable, by using watch 0x123400 and then type continue, to let Mach continue execution. The debugger will be entered again on any change in that variable. The watch is implemented in hardware, so it does not disturb or slow down execution at all. When you're [[running_a_system_in_QEMU|hurd/running/qemu]] you can directly [use GDB on the running kernel](http://www.nongnu.org/qemu/qemu-doc.html#SEC48). Alternatively you can use an approach like this one: add the following code snippet to `device/ds_routines.c`'s `ds_device_open` function, right at the top of the function, and modify the code as needed. void D (char *s) { switch (s[0] - '0') { case 0: printf ("Hello from %s!\n", __FUNCTION__); break; case 1: printf ("%s: Invoking task_collect_scan.\n", __FUNCTION__); extern void task_collect_scan (void); task_collect_scan (); break; default: printf ("No idea what you want me to do.\n"); break; } } if (name && name[0] == 'D') D (name + 1); Then boot your system and do something like this: # devprobe D0 Hello from D! # devprobe D1 D: Invoking task_collect_scan. # devprobe D2 No idea what you want me to do. This is especially useful if you need to manually trigger some stuff inside the running kernel, as with the *D1* example. If you're doing real low level debugging, you might want to put variations of the following snipped into the code, this code will write a `#` character at line `[LINE]`, column `[COLUMN]` on the screen: *((char *) 0xb8000 + 2 * ([LINE] * 80 + [COLUMN])) = '#'; halt_cpu (); The call of `halt_cpu` will -- as the name suggests -- halt the system afterwards. This might be what you want or it might not, but it is needed at some place when running the kernel inside QEMU, as QEMU somehow decides not to update its display buffer anymore under certain conditions. IRC, freenode, #hurd, 2011-07-14: one ugly trick i use when printf isn't available is to halt the cpu then use info registers to know where the cpu is halted and you'll know if you reached that code or not (info registers is a qemu command)