unique debugging challenges. Kernel code cannot be easily executed under a debugger, nor can it be easily traced, because it is a set of functionalities not related to a specific process Here, we list the configuration options that should be enabled for kernels used for development. Except where specified otherwise, all of these options are found under the “kernel hacking” menu in whatever kernel configuration tool you prefer. Note that some of these options are not supported by all architectures. CONFIG_DEBUG_KERNEL This option just makes other debugging options available; it should be turned on but does not, by itself, enable any features. CONFIG_DEBUG_SLAB This crucial option turns on several types of checks in the kernel memory allocation functions; with these checks enabled, it is possible to detect a number of memory overrun and missing initialization errors. CONFIG_DEBUG_PAGEALLOC Full pages are removed from the kernel address space when freed. This option can slow things down significantly, but it can also quickly point out certain kinds of memory corruption errors. CONFIG_DEBUG_SPINLOCK With this option enabled, the kernel catches operations on uninitialized spinlocks and various other errors (such as unlocking a lock twice). Debugging by Printing The most common debugging technique is monitoring, which in applications programming is done by calling printf at suitable points. printk We used the printk function in earlier chapters with the simplifying assumption that it works like printf. printk(KERN_DEBUG "Here I am: %s:%i\n", __FILE__, __LINE__); printk(KERN_CRIT "I'm trashed; giving up on %p\n", ptr); KERN_CRIT Critical conditions, often related to serious hardware or software failures. KERN_DEBUG Used for debugging messages. Printing Device Numbers Occasionally, when printing a message from a driver, you will want to print the device number associated with the hardware of interest. It is not particularly hard to print the major and minor numbers, but, in the interest of consistency, the kernel provides a couple of utility macros (defined in <linux/kdev_t.h>) for this purpose: int print_dev_t(char *buffer, dev_t dev); char *format_dev_t(char *buffer, dev_t dev); Both macros encode the device number into the given buffer; the only difference is that print_dev_t returns the number of characters printed, while format_dev_t returns buffer; therefore, it can be used as a parameter to a printk call directly, although one must remember that printk doesn’t flush until a trailing newline is provided.