GDB Debugger Info
GDB Debugger Info
html
The purpose of a debugger is to allow you to see what is going on inside your C program while it runs. In addition, you can
use gdb to see what your program was doing at the moment it crashed.
Here are some of the usful actions that gdb can perform:
For C and C++ programs, gdb and ddd are debuggers that you can use. ddd is a easy-to-use GUI wrapper around an
inferior debugger (gdb for GNU compiled C or C++ code). ddd allows you to interact with the debugger by using either
GUI menu options or the under-lying debugger's command line interface. In addition, ddd automatically displays source
code when breakpoints are reached.
There are some example programs and some documentation on using gdb to debug them that you can copy from here:
/home/newhall/public/gdb_examples/
C and C++ programs compiled with the GNU compiler and the -g option can be debugged using GNU's debugger gdb
(actually, you can use gdb on code that is not compiled with -g, but unless you like trying to figure out how assembly code
sequences map to your source code I wouldn't recommend doing so). Also, do not compile with an optimization flag (i.e.
don't use -O2), or gdb will have a hard time mapping optimized machine code to your source code. For example:
% gcc -g myprog.c
1 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
% gdb a.out
If your program terminates with an error, then the operating system will often dump a core file that contains information
about the state of the program when it crashed. gdb can be used to examine the contents of a core file:
% gdb core a.out
One good way to get started when you are trying to track down a bug, is to set breakpoints at the start of every function.
In this way, you will quickly be able to determine which function has the problem. Then you can restart the program and
step through the offending function line-by-line until you locate the problem exactly.
% ddd a.out
break
break <line> Sets breakpoint at line number <line>
break <func-name> Sets breakpoint at beginning of function <func-name>
break main Sets breakpoint at beginning of program
2 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
print <exp> (or inspect <exp> Displays the value of expression <exp>
You can also use register values and values stored in memory locations in expressions
print $eax # print the value stored in the eax register
print *(int *)0x8ff4bc10 # print the int value stored at memory address 0x8ff4bc10
x <var, memory address> displays the contents of the memory location given a variable name or a memory address.
Can display in diffent formats (as an int, a char, a string, ...)
# can also use the address of a varible as the argument (say temp is an int)
x &temp
# NOTE: format in examine is sticky, for example if you use the command x/c
# subsequent executions of x will use /c format. you therefore need to
# explicitly change the format to /d /c /s etc. for interpreting memory
# contents as differnt type from the previous call to x
gdb has a large set of info X commands for displaying information about different types of runtime state and about
debugger state. Here is how to list all the info commands in help, and a description of what a few of the info commands
do:
(gdb) help status # lists a bunch of info X commands
(gdb) info frame # list information about the current stack frame
(gdb) info locals # list local variable values of current stack frame
(gdb) info args # list argument values of current stack frame
(gdb) info registers # list register values
(gdb) info breakpoints # list status of all breakpoints
using gdb to debug assembly code and examine memory and register values
ddd is probably easier to use when steping through assembly code than gdb because you can have separate windows that
3 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
show the disassembled code, the register values, and the gdb prompt.
Here are some gdb commands that are useful for debugging at the assembly code level:
info
info registers # list register values
print
print $eax # print the value stored in the eax register
print *(int *)0x8ff4bc10 # print the int value stored at memory address 0x8ff4bc10
display $eax
1. Run 1 is a gdb run of badprog.c. It demonstrates some common gdb commands, and it finds one of the bugs in this
program...there are others.
2. Run 2 is a gdb run of segfaulter.c. It demonstrates how to find out where your program is segfaulting (and perhaps
why...although valgrind will help more with this type of error).
Run 1: badprog.c
4 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
(gdb) break main #-- set a breakpoint at the begining of the program's execution
(gdb) list #-- list the source code near the break point
31 return 0;
32 }
33
34 int main(int argc, char *argv[]) {
35
36 int arr[5] = { 17, 21, 44, 2, 60 };
37
38 int max = arr[0];
39
40 if ( findAndReturnMax(arr, 5, max) != 0 ) {
11 // this function should find the largest element in the array and
12 // "return" it through max
13 // array: array of integer values
14 // len: size of the array
15 // max: set to the largest value in the array
16 // reuturns: 0 on success and non-zero on an error
17 //
18 int findAndReturnMax(int *array1, int len, int max) {
19
20 int i;
(gdb) #-- hitting Enter executes the previous command (next in this case)
40 if ( findAndReturnMax(arr, 5, max) != 0 ) {
#-- also you can use the up and down arrows to scroll through previous commands
5 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
(gdb) print array1[0] #-- lets see what the param values are
$3 = 17
(gdb) p max
$4 = 17
(gdb) list
17 //
18 int findAndReturnMax(int *array1, int len, int max) {
19
20 int i;
21
22 if(!array1 || (len <=0) ) {
23 return -1;
24 }
25 max = array1[0];
26 for(i=1; i <= len; i++) {
Breakpoint 2, findAndReturnMax (array1=0xbfc5cb3c, len=5, max=17) #-- gdb hits the next breakpoint
at badprog.c:26
26 for(i=1; i <= len; i++) {
(gdb) p i
$5 = 0
(gdb) display max #-- display will print out the value everytime we hit a breakpoint
1: max = 17
(gdb) cont
Continuing.
(gdb) cont
Continuing.
6 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
(gdb) cont
Continuing.
#-- findAndReturnMax is the active function at line 27, it was called by main at line 40:
#0 findAndReturnMax (array1=0xbfd043ec, len=5, max=60) at badprog.c:27
#1 0x08048479 in main () at badprog.c:40
frame 1 #-- move into main's calling context (stack frame 1) to examine main's state
#1 0x08048479 in main () at badprog.c:40
40 if ( findAndReturnMax(arr, 5, max) != 0 ) {
Run 2: segfaulter.c
% gdb segfaulter
(gdb) run #-- just run segfaulter and let it seg fault
7 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
15 array[i] = i;
16 }
17 return 0;
18 }
19
(gdb) p array[0] #--- let's print out some values and see what's going on
Cannot access memory at address 0x0
(gdb) p array
$1 = (int *) 0x0
(gdb) frame 1 #--- let's see what main is passing to this funtion
(gdb) print arr #--- print out arr's value (what we pass to initfunc)
$2 = (int *) 0x0
#--- oops, we are passing NULL to initfunc...we forgot to initialize arr to point to valid memory
gdb supports command line completion; by typing in a prefix you can hit TAB and gdb will try to complete the command
line for you.
Also, you can give just the unique prefix of a command as the command and gdb will execute it. For example, rather
than entering the command print x, you can just enter p x to print out the value of x.
The up and down arrow keys can be used to scroll through previous command lines, so you do not need to re-type them
each time.
If you just hit RETURN at the gdb prompt, gdb will execute the most recent previous command again. This is particularly
useful if you are steping through the execution, then you don't have to type next each time you want to execute the next
instruction, you can just type it one time and then hit RETURN.
Setting conditional breakpoints and some issues with setting breakpoints in C++ code
conditional breakpoints
A conditional breakpoint is one that only transfers control to gdb when a certain condition is true. This can be very useful
when you only want gdb control after iteration 1000 of a loop, for example.
To set a condition on a breakpoint, use the condition command with the number of the breakpoint followed by the condition
on which to trigger the breakpoint. Here is an example where I'm setting a conditional breakpoint that will only be
triggered when the condition (i >= 1000) is true:
8 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
One complication with gdb and C++ programs, is that you need to specify methods and data members using the
"classname::" prefix. In addition, you often need to use a leading ' before a name for gdb to find the symbol, and if
methods are overloaded, you need to specify which method it is by listing its full prototype (actually, if you hit TAB gdb
will list all possible matches for you and you can pick one of those).
For example, to set a break point in funciton pinPage of the BufMgr class, I'd do the following:
This looks pretty icky, but really I just type break 'BufMgr::p then hit TAB for automatic completion.
(gdb) break 'BufMgr:: <tab>
will list all methods of the BufMgr class, then you can just pick from the list the method you want to put the breakpoint in.
Within gdb you can invoke "make" to rebuid your executable (assuming that you have a makefile to build your program).
This is a nice feature in the case when you have many breakpoints set and do not want to exit gdb, recompile, re-start gdb
with the new a.out, and reset all the breakpoints. However, keep in mind that modifying and recompiling your source code
from within gdb may result in your breakpoints not being where you think they should be (adding/removing lines of source
code can result in your in your breakpoints no longer being where you want them to be in terms of the new version of your
source code). You can use the disable or delete commands to disable or delete old breakpoints.
# OR alternative syntax:
At this point the process is stopped by gdb; you have the gdb prompt that you can use issue gdb commands like
setting breakpoints, or printing out program state before continuing execution.
signal control
Sometimes your process receives signals and you would like to have gdb perform some action when certain signals are
delived to the debugged process. For example, if your program issues a bad adress, it will receive a SIGBUS signal and
9 of 10 10/22/2013 09:29 PM
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_gdb.html
usually exit. The default behavior of gdb on a SIGBUS it to let the process exit. If, however, you want to examine
program state when it recieves a SIGBUS, you can specify that gdb handle this singal differently:
(gdb) handle SIGBUS stop # if program gets a SIGBUS, gdb gets control
(gdb) info SIGALRM # list info just for the SIGALRM signal
Running ddd creates a .ddd directory in your home directory and will save settings to files here, so that you don't need to
reset all your preferences from scratch. You can click and drag to change the sizes of subwindows and choose Menu
options to display (or not) certain menus, register values, machine code, etc.
To view assembly code: under Source menu choose "Display Machine Code" or Alt+4
If ddd hangs with "Waiting until gdb ready" message, then one way to fix this is to wipe out your .ddd directory (you
will lose all your saved settings):
rm -rf ~/.ddd
gdb Links
10 of 10 10/22/2013 09:29 PM