Please note, this page is under development at the moment and may be incomplete or possibly use incorrect terminology
When testing, a "bug", or behavior contrary to design or expectation, may be found. Debugging is the process of finding the source of the bug in order to remove it.
As always, there are multiple means by which to debug a program that vary, among other things, in their level of complexity and detail by which information may be examined.
Inserting statements like printf() and puts() to watch the progress and/or data of the program is the least technical method
--Insert stuff here about using a debugger with a 32/64b program.
Both qemu and bochs have the capability of a gdbstub, which allow you to connect gdb, the GNU Debugger, to the qemu/bochs process and examine what the VM sees.
Debugger 16-bit Segmented
(Or the real reason I built this page. --Gene)
16-bit segmented mode, also known as Real Mode, is recognize as addressing with 2 registers, a segment and an offset, each 16 bits long, and staggered to form a 20 bit address (segment * 10h + offset = address). This is the operating mode of the boot sector, the secondary loader (for disk-based variants in Syslinux-4.00 as of 2010-06-21), most (but I believe all) of the Syslinux core assembly code and COMBOOT modules.
Unfortunately, gdb is not effective at debugging 16-bit segmented code. Attempting to utilize qemu or bochs with gdb will only lead to frustration.
However, bochs has an internal debugger available. Unfortunately, it's mutually exclusive of the gdbstub at compile time and most distributions compile in the gdbstub instead of the internal debugger (which is probably a good choice _most_ of the time).
Use the source
Quite literally. Grab the source for bochs (on 2010-06-21, 2.4.5 is the current stable), the needed development libraries (the configure script will warn you nicely; if it says libraries are missing, it means development libraries of course). You'll want to configure using './configure --enable-debugger --enable-disasm' to enable the debugger and disassembler. '--enable-readline' is helpful in the debugger for editing the command line and history. You can also add '--enable-ne2000' and '--enable-pnic' if you're interested in PXELINUX. Next, compile it ('make all'). See also Setting Up Bochs.
I've tried to build bfe (bochs debugger front end) but at this time have not figured out what I'm missing.
After launching, it will come up to the "start menu" (unless -q is specified). If it's fully configured, "Begin Simulation". At this point, it will dump you to the debugger prompt. Your first friend here is 'help' (also as 'h') to list the possible commands. 'h b' will list help information for 'b' (breakpoint).
See also the official manual here (although as of 2010-08-01, it appears to be out of date and the internal help is current).
Breakpoints are a way to stop the debugger at an exact code point. The first one to be aware of is 0x7c00 ('b 0x7c00'). This is the code entry point for all variants. If you're debugging a boot sector (for a disk-based variant or ISOLINUX), this is a great starting breakpoint. This makes it execute through all of the BIOS related initialization code without stopping.
If you don't want to look at the code in an interrupt, try setting a breakpoint at the return point.
As of 2010-06-21, Syslinux 4.00-pre55 disk-based variants used a boot loader to a secondary loader (starting at address 0x8000).
For additional addresses within the Syslinux core, look at the .lst file for the variant you are examining as it has the correct addresses. Please note this requires currently that you compile Syslinux yourself at this time.
For the loading and entry into a COM32 module, search for call com32_entry in the .lst file of the variant you are using.
'c' will tell it to continue on if it's been interrupted (including the initial prompt).
's' or 's #' will step forward a certain number of instructions (default 1). This will include the code you're examining and any interrupt calls.
'u' or 'disasm' will disassemble the current instruction. 'u /count' disassembles count instructions
'u start' will disassemble the instruction at the location start. 'u start end' will disassemble instructions from location start inclusive to end exclusive.
'r' will dump the state of all of the "standard" registers, eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags.
'sreg' will dump the segment registers es, cs, ss, ds, fs, gs (and information about those segments)
'set reg = expr' will set the register reg to the value of the expression expr (as of 2010-08-01, the manual states it only works on general purpose integer registers but it does also work on the segment registers).
'xp /nuf addr' is a way to examine the contents of memory. 'xp /4wx 0x7c00' will dump 4 "words" (32b) in heXidecimal starting at 0x7c00.