Before using gdb, you should ask nasm to provide some debugging information. This is done with the -g switch. For example,
If your program contains portions written in C, those portions should be compiled using the -g option to retain debugging information in the a.out file.
The complete documentation for gdb is available on the Linux system using the info command:
You can now run your program inside gdb by typing "run" at the (gdb) prompt. However, the program will just behave exactly as it did when it ran under the Linux shell. The point of using a debugger is to set breakpoints where the execution of the program is halted. This returns you to the (gdb) prompt and you can use various gdb commands to examine the contents of the registers and/or memory. It is common to have breakpoints set at the beginning of a program, at the end of a program, at the top of a loop and anywhere you think the bug occurred in your program.
For example:
After execution of your program has been halted by a breakpoint, you can resume execution in several ways. The "cont" (continue) command resumes execution after the breakpoint. The execution continues until the next breakpoint is reached or the program terminates. Alternatively the single step commands "stepi" or "nexti" command may be used to execute a single machine instruction after the breakpoint. The difference between "stepi" and "nexti" arises when the next instruction is a function call. The "nexti" command will continue execution until the return from the function call (which might be never). On the other hand, the "stepi" command will enter the function. The command "where" will show where the execution of a program has halted.
To help you determine where to set the breakpoints, gdb also has a disassembler. The command:
Memory contents can be examined using the "x" command. The "x" command is optionally followed by a "/", a count field, a format field, a size field and finally a memory address. The count field is a number in decimal. The format field is a single letter with 'd' for decimal, 'x' for hexadecimal, 't' for binary and 'c' for ASCII. The size field is also a single letter with 'b' for byte, 'h' for 16-bit word (half word) and 'w' for a 32-bit word. For example, if your program has a label "msg", the following commands:
Sometimes, as you are tracing your program, you are really interested in the contents of a specific register. If you issue the command:
A very good use of the display command is to have the next instruction of the program printed whenever the program is halted:
Command | Example | Description |
---|---|---|
run | start program | |
quit | quit out of gdb | |
cont | continue execution after a break | |
break [addr] | break *_start+5 | sets a breakpoint |
delete [n] | delete 4 | removes nth breakpoint |
delete | removes all breakpoints | |
info break | lists all breakpoints | |
list _start | list a few lines of the source code around _start | |
list 7 | list 10 lines of the source code starting on line 7 | |
list 7, 20 | list lines 7 thru 20 of the source code | |
stepi | execute next instruction | |
stepi [n] | stepi 4 | execute next n instructions |
nexti | execute next instruction, stepping over function calls | |
nexti [n] | nexti 4 | execute next n instructions, stepping over function calls |
where | show where execution halted | |
disas [addr] | disas _start | disassemble instructions at given address |
info registers | dump contents of all registers | |
print/d [expr] | print/d $ecx | print expression in decimal |
print/x [expr] | print/x $ecx | print expression in hex |
print/t [expr] | print/t $ecx | print expression in binary |
x/NFU [addr] | x/12xw &msg | Examine contents of memory in given format |
display [expr] | display $eax | automatically print the expression each time the program is halted |
info display | show list of automatically displays | |
undisplay [n] | undisplay 1 | remove an automatic display |