Debugging ordinary programs is hard enough; kernel debugging is harder still. The following few paragraphs describes some common debugging tools and strategies that you may find useful.
nm | Dump symbol address, linkage types, and names. Useful for setting break points in Bochs or Qemu. | |
readelf | Dump ELF file metadata | |
objcopy | Translate object file formats | |
objdump | Dump object file metadata and disassembly | |
addr2line | Map pc to source line | |
| gdb | ptype | Dump type information |
| p sizeof | Type size | |
| p &((Foo*)0)->x | Member offset | |
| disass 0xaddr | Disassemble code | |
| genassym | Export constant C expression to assembly to avoid having to maintain them in two places at once. | |
| printf | Printf and primitive CGA console driver for the x86; includes "long long" arithmetic support. |
0xcafebabe,
0xba5eba11).
Print machine code in a fault handler or debugging statement and copy that code in to an array in a dummy C program to disassemble it with gdb. The C code looks something like this:
unsigned char code[] = { 0x90, 0x90, 0x90 };
Then in gdb disassemble code.
Add trap handlers for undefined opcodes and then drop ud2 instructions at various points. The trap handler can print out the faulting address, providing a cheap debugging print in places that printf cannot safely be called.