Debugging IA32 Assembly Code
with gdb (and ddd)

IA32 assembly, gdb disassemble

gdb disassemble and instruction stepping

With gdb you can execute individual IA32 instructions, examine register values, and disassemble functions.

This example runs through some gdb instruction level debugging using the very simple C program example:

// gcc -m32 -S simpleops.c   
void main() {

   int x, y;

   x = 1;
   x = x + 2;
   x = x - 14;
   y = x*100;
   x = x + y * 6;
Compile this using:
  gcc -m32 -o simpleops simpleops.c
With this added flag, the generated IA32 code will be a little easier to read:
 gcc -m32 -fno-asynchronous-unwind-tables -o simpleops simpleops.c

Start gdb on the executable simpleops. Add a breakpoint in main, and then start runing the program with (gdb) run:

gdb simipleops
(gdb) break main
(gdb) run
In gdb you can disassemble code using the disass command:
(gdb) disass main
You can set a break point at a specific instruction:
(gdb) break *0x080483c1   # set breakpoint at specified address 
(gdb) cont
(gdb) disass 
And you can step or next at the instruction level using ni or si (si steps into function calls, ni skips over them):
(gdb) ni	  # execute the next instruction then gdb gets control again 
(gdb) ni
(gdb) ni
(gdb) ni
(gdb) ni
(gdb) disass
You can print out the values of individual registers like this:
(gdb) print $eax
You can also view all register values:
(gdb) info registers
You can also use the display command to automatically display values each time a breakpoint is reached:
(gdb) display $eax
(gdb) display $edx


ddd is a gui interface on top of a debugger (gdb in this case). It has a nicer interface for viewing assembly, registers, and stepping through IA32 instruction execution than command line gdb:
ddd simpleops
The gdb prompt is in the bottom window. There are also menu options and buttons for gdb commands, but I find using the gdb prompt at the bottom easier to use.

You can view the assembly code by selecting the View->Machine Code Window menu option. You will want to resize this part to make it larger.

You can view the register values as the program runs (choose Status->Registers to open the register window).

Quick summary of some useful gdb commands for debugging at the assembly code level (showing made-up examples):

  ddd a.out
  (gdb) break main
  (gdb) run  6              # run with the command line argument 6
  (gdb) disass main         # disassemble the main function
  (gdb) break sum           # set a break point at the beginning of a function
  (gdb) cont                # continue execution of the program
  (gdb) break *0x0804851a   # set a break point at memory address 0x0804851a
  (gdb) ni                  # execute the next instruction
  (gdb) si                  # step into a function call (step instruction)
  (gdb) info registers      # list the register contents
  (gdb) p $eax              # print the value stored in register %eax
  (gdb) p  *(int *)($ebp+8) # print out value of an int at addr (%ebp+8)
  (gdb) x/wd $ebp+8         # examine the contents of memory at the given address
                            # as an int (w: word-size value d: in decimal) 
                            # display type in x is sticky: subsequent x commands
                            # will display values in decimal until another type is
                            # specified (ex. x/a $ebp+8  # as an address in hex)
  (gdb) x/s 0x0800004       # examine contents of memory at address as a string
  (gdb) x/wd 0xff5634       # after x/s, the unit size is 1 byte, so if want
                            # to examine as an int specify both the width w and d 

More resources: