|
CEG 333: Introduction to UnixPrabhaker MatetiGDB |
The GNU Debugger (GDB) is a free, high-quality system for examining the innards of a running program. Like GCC, it is a free alternative to commercial Unix debuggers, which share a similar interface.
To start the debugger and load a program, type gdb
[--args] [PROGRAM], where PROGRAM is the compiled
executable to be debugged. PROGRAM can be in the current directory
or anywhere in the path. The program GDB is debugging can be
specified later or changed with the file PROGRAM
command.
If the --args option is given, GDB will pass any arguments
after the program name to the program. Don't put program arguments
on the command line without this. Otherwise, GDB will think those
arguments are meant for it and get confused! (Arguments can also
be given later, to run)
Note: GDB won't work properly with programs that were
compiled without debugging symbols (extra information about
the code). Be sure to use the -g compiler flag!
The standard Unix debugging interface is a command line, with it's own set of commands. These may be entered at the "(gdb)" prompt, and are not the same as those used by bash.
Most commands can be abbreviated, frequently with just the first letter (for example "c" for "continue"). If an abbreviation could mean more than one command, GDB will ask which is meant.
| Command | Use |
backtrace |
Show the call stack. |
break PLACE |
Set a breakpoint at given line number or function name.
Execution will stop at that point so the program's state may
be examined. For example, break main to stop at
the first line of the program, or break 289 to
stop on line 289 every time the program is run. |
cont |
Continue execution until the next breakpoint. |
delete [NUMBER...] |
Remove a breakpoint, watchpoint, or auto-display. |
disable [NUMBER...] |
Temporarily disable a breakpoint, watchpoint, or auto-display. |
display EXPRESSION |
Automatically display the value of the given expression whenever execution stops. Use this to read the value |
file PROGRAM |
(Re)load the program. This must be used if it's recompiled during a debugging session. |
help |
With an argument (such as a command name), show help on that topic. |
list [WHERE] |
Prints part of a program. WHERE can be a line number, a function, or FILE:LINENUM. Without arguments, prints the lines following the last listing, or with a "-" lists the lines before. |
next |
Execute the next line, but don't step into functions. |
print EXPRESSION |
Print the current value of the given expression once. |
quit |
Quit GDB. |
run [ARGUMENTS] |
Start the program's execution. Type any command-line arguments after it, in order. Warning: never give the name of the executable here, only its arguments. |
step |
Execute the next line. If it is a function call, GDB will go through every line of the function. |
watch EXPRESSION |
Set a watchpoint on the given variable or expression. Whenever the value of that expression changes, execution stops and the old and new values are displayed. |
display and
watch)The difference between "display" and "watch" can be confusing at first, but it's very important important.
For example, say a programmer desires to show the current value of an expression every time the program passes through a certain point. "display" and a breakpoint should always be used for this case. "watch" will show the value only when it changes, and not necessarily in the important part of the program.
GDB evaluates expressions when the command is given. So when
using "display", any variable names in the expression
must be in scope. A breakpoint can be set to stop execution where
the variables come into scope, after which display
can be set.
Consider the following program, pow.cpp. It crashes after the line 12 printf. Why?
#include <cstdio>
#include <cstring>
using namespace std;
int pow(int x, int y) {
return x * pow(x, y-1);
}
int main(int argc, char *argv[]) {
int x = 3;
printf("Line 12: x: %i\n", x);
x = pow(x, 3);
printf("Line 14: x: %i\n", x);
return 0;
}
Start the debugger with gdb pow, and run the
program to catch the crash in action:
(gdb) run
Starting program: /tmp/gdb_eg/pow
Line 12: x: 3
Program received signal SIGSEGV, Segmentation fault.
0x080484c8 in pow (x=3, y=-524111) at /tmp/gdb_eg/pow.cpp:7
7 return x * pow(x, y-1);
If the bug is obvious, this alone might be enough information. If not, GDB can provide a list of all the recursive function calls that got the program to this point, in reverse order:
(gdb) backtrace
#0 0x080484c8 in pow (x=3, y=-524111) at /tmp/gdb_eg/pow.cpp:7
#1 0x080484cd in pow (x=3, y=-524110) at /tmp/gdb_eg/pow.cpp:7
#2 0x080484cd in pow (x=3, y=-524109) at /tmp/gdb_eg/pow.cpp:7
#3 0x080484cd in pow (x=3, y=-524108) at /tmp/gdb_eg/pow.cpp:7
#4 0x080484cd in pow (x=3, y=-524107) at /tmp/gdb_eg/pow.cpp:7
#5 0x080484cd in pow (x=3, y=-524106) at /tmp/gdb_eg/pow.cpp:7
#6 0x080484cd in pow (x=3, y=-524105) at /tmp/gdb_eg/pow.cpp:7
#7 0x080484cd in pow (x=3, y=-524104) at /tmp/gdb_eg/pow.cpp:7
#8 0x080484cd in pow (x=3, y=-524103) at /tmp/gdb_eg/pow.cpp:7
#9 0x080484cd in pow (x=3, y=-524102) at /tmp/gdb_eg/pow.cpp:7
#10 0x080484cd in pow (x=3, y=-524101) at /tmp/gdb_eg/pow.cpp:7
#11 0x080484cd in pow (x=3, y=-524100) at /tmp/gdb_eg/pow.cpp:7
#12 0x080484cd in pow (x=3, y=-524099) at /tmp/gdb_eg/pow.cpp:7
#13 0x080484cd in pow (x=3, y=-524098) at /tmp/gdb_eg/pow.cpp:7
#14 0x080484cd in pow (x=3, y=-524097) at /tmp/gdb_eg/pow.cpp:7
#15 0x080484cd in pow (x=3, y=-524096) at /tmp/gdb_eg/pow.cpp:7
#16 0x080484cd in pow (x=3, y=-524095) at /tmp/gdb_eg/pow.cpp:7
#17 0x080484cd in pow (x=3, y=-524094) at /tmp/gdb_eg/pow.cpp:7
#18 0x080484cd in pow (x=3, y=-524093) at /tmp/gdb_eg/pow.cpp:7
#19 0x080484cd in pow (x=3, y=-524092) at /tmp/gdb_eg/pow.cpp:7
#20 0x080484cd in pow (x=3, y=-524091) at /tmp/gdb_eg/pow.cpp:7
#21 0x080484cd in pow (x=3, y=-524090) at /tmp/gdb_eg/pow.cpp:7
#22 0x080484cd in pow (x=3, y=-524089) at /tmp/gdb_eg/pow.cpp:7
---Type <return> to continue, or q <return> to quit---q
Quit
Oops. Why is it trying to raise x to a negative power? y is only supposed to be 3!
To examine the program as it goes wrong, set a breakpoint before the first call to pow() and re-run it, using "step" to go through line by line:
(gdb) break 11
Breakpoint 1 at 0x80484f7: file /tmp/gdb_eg/pow.cpp, line 11.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/gdb_eg/pow
Breakpoint 1, main (argc=1, argv=0xbffff5e4) at /tmp/gdb_eg/pow.cpp:11
11 printf("Line 12: x: %i\n", x);
(gdb) step
Line 12: x: 3
12 x = pow(x, 3);
(gdb) s
pow (x=3, y=3) at /tmp/gdb_eg/pow.cpp:6
6 return x * pow(x, y-1);
It might be helpful to set a new breakpoint here and a display on y, since that variable seems to be the source of the problem:
(gdb) break 6
Breakpoint 2 at 0x80484ba: file /tmp/gdb_eg/pow.cpp, line 6.
(gdb) display y
1: y = 3
(gdb) c
Continuing.
Breakpoint 2, pow (x=3, y=2) at /tmp/gdb_eg/pow.cpp:6
6 return x * pow(x, y-1);
1: y = 2
(gdb) c
Continuing.
Breakpoint 2, pow (x=3, y=1) at /tmp/gdb_eg/pow.cpp:6
6 return x * pow(x, y-1);
1: y = 1
(gdb) c
Continuing.
Breakpoint 2, pow (x=3, y=0) at /tmp/gdb_eg/pow.cpp:6
6 return x * pow(x, y-1);
1: y = 0
(gdb) c
Continuing.
Breakpoint 2, pow (x=3, y=-1) at /tmp/gdb_eg/pow.cpp:6
6 return x * pow(x, y-1);
1: y = -1
Oh. There's no end condition for the recursion! Going back to the source, the program can now be fixed:
int pow(int x, int y) {
if (y != 1) return x * pow(x, y-1);
else return x;
}
GDB can be used for a few more tests, just to make sure:
(gdb) r
Starting program: /tmp/gdb_eg/pow
Line 12: x: 3
Line 14: x: 27
Program exited normally.
(gdb) break 15
Breakpoint 1 at 0x8048547: file /tmp/gdb_eg/pow.cpp, line 15.
(gdb) r
Starting program: /tmp/gdb_eg/pow
Line 12: x: 3
Line 14: x: 27
Breakpoint 1, main (argc=1, argv=0xbffff5e4) at /tmp/gdb_eg/pow.cpp:15
15 return 0;
(gdb) set var x=pow(4,4)
(gdb) print x
$1 = 256
(gdb) c
Continuing.
Program exited normally.
Note the use of an arbitrary function call to alter a variable.