gdb (the command-line debugger)
Unlike the debugger you may have used in cs106A or cs106B, we will be
using a command-line debugger, called gdb (the "Gnu Debugger"). gdb
is a powerful tool, and you will use it very frequently in cs107. It
would be a good idea to start familiarizing yourself with how to use
gdb as soon as possible.
This page will list the basic gdb commands you will need to use
as you progress through cs107. However, it takes practice to become
proficient in using the tool, and gdb is a large program that has
a tremendous number of features.
Compiling for gdb: gcc does not automatically put debugging
information into the executable program, but our Makefiles
all include the -g -Og flags that give gdb information about
our programs so we can use the debugger efficiently. If we want to
compile our program directly, we write:
$ gcc -g -Og square.c -o square
$
Running gdb: To run gdb, you generally provide it with a program:
$ gdb square
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from square...done.
(gdb)
The (gdb) prompt is where you start typing your commands.
In gdb, if you simply type the enter key, the last command will
be re-run. This is nice if you are stepping through a program
line-by-line: you can use the next command once, and then hitting
the enter key will re-run the next command again without you having
to type the command.
Also, many commands can be abbreviated, as noted below.
There are a number of commands that you should be familiar with:
help command(abbr:h command) andapropos keyword(abbr: `appr keyword): Provides help (information) about a particular command or keyword.info x(abbr:i x): provides information about your program, such as the breakpoints, the functions, etc.run(abbr:r): Theruncommand runs your program. You can enter command line arguments after the command, if your program requires them. If you are already running your program and you want to re-run it, you should answeryto the prompt that says, "The program being debugged has been started already. // Start it from the beginning? (y or n)"list(abbr:l): Thelistcommand lists your program either from the beginning, or with a range around where you are currently stopped.next(abbr:n): Thenextcommand steps to the next program line and completely runs functions. This is important: if you have a function (even one you didn't write) and you usenext, the function will run to completion, and will stop at the next line after the function (unless there is a breakpoint inside the function).step(abbr:s): Thestepcommand is similar tonext, but it will step into functions. This means that it will attempt to go to the first line in a function if there is a function on the current line. Importantly, it will also take you into functions you didn't write (such asprintf), which can be annoying (you should usenextinstead). If you do accidentally step into a function, you can use thefinishcommand (see below) to finish the function immediately and go back to the next line after the function.continue(abbr:c): This will continue running the program until the next breakpoint or until the program ends.print x(abbr:p x): This very important command lets you see the value of a variable when you are stopped in a program. If you see the error "No symbol xxxx in current context", or the error, "optimized out", you probably aren't in a place in the program where you can read the variable.break x(abbr:b x): This will put a breakpoint in the program at a function or a particular line. If you have multiple files, you should usebreak file:lineNum.clearanddelete x: used to delete breakpoints.clearremoves the breakpoint on a particular line, anddelete xremoves a breakpoint by line number. Useinfo breakpointsto see all breakpoints.where(abbr:whe): This will print a stack trace to let you know where in the program you are currently stopped. This is a useful command if your program has a segmentation fault: thewherecommand will tell you the last place in your program that had the problem (sometimes you need to look at the entire stack trace to go back to the last line your program tried to execute).upanddown: These commands allow you to go up and down the stack trace. For instance, if you are inside a function and what to see the status of variables from the calling function, you can useupto place the program into the calling function, and then usep variableto look at the state of the program in that function. You would then usedownto go back to the function that was called.finish: runs a function until it completes, which is helpful if you accidentally step into a function.disassemble(abbr:disas): dissassembles your program into assembly language. We will be discussing this in depth in cs107.ctrl-x, ctrl-a(go into or leave "TUI" mode):gdbhas a mode that shows you source code, or assembly output in a manner that allows you to scroll up and down. It is useful but sometimes can be a bit buggy. You will want to learn the "ctrl-L" command to refresh the display.
The following capture is a typical gdb session. Lines that start with
(gdb) # some text are comments.
We will be looking at this simple program below:
#include<stdlib.h>
#include<stdio.h>
int square(int x);
int main(int argc, char *argv[]) {
printf("This program will square an integer.\n");
// the program should have one number as an argument
if (argc != 2) {
printf("Usage:\n\t./square number\n");
return 0;
}
// the first argument after the filename
int numToSquare = atoi(argv[1]);
int squaredNum = square(numToSquare);
printf("%d squared is %d\n",numToSquare,squaredNum);
return 0;
}
int square(int x) {
int sq = x * x;
return sq;
}
(gdb) # the "run" command runs the program, and we need to remember to put a command line argument if we need one. Let's try it without an argument:
(gdb) run
Starting program: /afs/.ir.stanford.edu/users/c/g/cgregg/cs107/assignments/assign5/square
This program will square an integer.
Usage:
./square number
[Inferior 1 (process 14146) exited normally]
(gdb)
(gdb) # the program caught that we tried to run without a number.
(gdb) # let's run it again with 25 as the argument:
(gdb) run 25
Starting program: /afs/.ir.stanford.edu/users/c/g/cgregg/cs107/assignments/assign5/square 25
This program will square an integer.
25 squared is 625
[Inferior 1 (process 14132) exited normally]
(gdb) # we successfully ran the program. To look at the program, you can
(gdb) # type 'list' or just 'l':
(gdb) l
1 #include<stdlib.h>
2 #include<stdio.h>
3
4 int square(int x);
5
6 int main(int argc, char *argv[]) {
7 printf("This program will square an integer.\n");
8
9 // the program should have one number as an argument
10 if (argc != 2) {
(gdb) # we type the return key to see the next lines, or just 'l' again:
(gdb) l
11 printf("Usage:\n\t./square number\n");
12 return 0;
13 }
14
15 // the first argument after the filename
16 int numToSquare = atoi(argv[1]);
17
18 int squaredNum = square(numToSquare);
19
20 printf("%d squared is %d\n",numToSquare,squaredNum);
(gdb)
21
22 return 0;
23 }
24
25
26 int square(int x) {
27 int sq = x * x;
28 return sq;
29 }
30
(gdb) # when debugging, we often want to stop at a particular place
(gdb) # in our code. We can set breakpoints at a line, or at a function.
(gdb) break main
Breakpoint 1 at 0x4005f3: file square.c, line 6.
(gdb) break 20
Breakpoint 2 at 0x40064e: file square.c, line 20.
(gdb) # now there are two breakpoints in the code. When we run the program
(gdb) # again, it will stop on the first line:
(gdb) run 25
Starting program: /afs/.ir.stanford.edu/users/c/g/cgregg/cs107/assignments/assign5/square 25
Breakpoint 1, main (argc=2, argv=0x7fffffffeab8) at square.c:6
6 int main(int argc, char *argv[]) {
(gdb) # now we are stopped. A nice command is the "where" command to tell
(gdb) # you exactly where you stopped:
(gdb) where
#0 main (argc=2, argv=0x7fffffffeab8) at square.c:6
(gdb) # if we type "l" again, we will get a list surrounding that line:
(gdb) l
1 #include<stdlib.h>
2 #include<stdio.h>
3
4 int square(int x);
5
6 int main(int argc, char *argv[]) {
7 printf("This program will square an integer.\n");
8
9 // the program should have one number as an argument
10 if (argc != 2) {
(gdb) # there are three commands that will continue the program.
(gdb) # the first command is "next" (or just "n"), which is the
(gdb) # "step over" command. It will run one line in your program, and
(gdb) # it will step over functions -- i.e., it will run a function
(gdb) # and not go into it.
(gdb) n
7 printf("This program will square an integer.\n");
(gdb) n
This program will square an integer.
10 if (argc != 2) {
(gdb) # now we are on line 10. We can use a different command, "step" to
(gdb) # go forward, as well, but "step" will go into a function if there
(gdb) # is a function to go into:
(gdb) s
11 printf("Usage:\n\t./square number\n");
(gdb) s
printf (__fmt=<optimized out>)
at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
104 return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
(gdb) # oops! We stepped into the "printf" function! We can get back to our
(gdb) # program by typing the "finish" command:
(gdb) finish
Run till exit from #0 printf (__fmt=<optimized out>)
at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
Usage:
./square number
12 return 0;
(gdb) # The final way to continue is to type "continue", which runs the
(gdb) # program to completion, or to the next breakpoint.
(gdb) continue
Continuing.
Breakpoint 2, main (argc=<optimized out>, argv=0x7fffffffeab8) at square.c:23
23 }
(gdb) continue
Continuing.
[Inferior 1 (process 14154) exited normally]
(gdb) # let's run it again with the proper argument
(gdb) run 25
Starting program: /afs/.ir.stanford.edu/users/c/g/cgregg/cs107/assignments/assign5/square 25
Breakpoint 1, main (argc=2, argv=0x7fffffffeab8) at square.c:6
6 int main(int argc, char *argv[]) {
(gdb) n
7 printf("This program will square an integer.\n");
(gdb) n
This program will square an integer.
10 if (argc != 2) {
(gdb) n
16 int numToSquare = atoi(argv[1]);
(gdb) n
18 int squaredNum = square(numToSquare);
(gdb) # now if we want to step into the square() function, we can, with s
(gdb) s
square (x=25) at square.c:27
27 int sq = x * x;
(gdb) where
#0 square (x=25) at square.c:27
#1 0x0000000000400636 in main (argc=<optimized out>, argv=0x7fffffffeab8)
at square.c:18
(gdb) # the where command gives us a stack trace, and we can see that
(gdb) # we are inside the square function, on line 27.
(gdb) # We can take a look at variables here, too, with the 'p' command:
(gdb) p x
$1 = 25
(gdb) # "p x" says "print x"
(gdb) # let's list the area around where we stopped
(gdb) l
22 return 0;
23 }
24
25
26 int square(int x) {
27 int sq = x * x;
28 return sq;
29 }
30
31
(gdb) where
#0 square (x=25) at square.c:27
#1 0x0000000000400636 in main (argc=<optimized out>, argv=0x7fffffffeab8)
at square.c:18
(gdb) # we can go one step forward using next or step
(gdb) n
29 }
(gdb) p sq
$2 = 625
(gdb) # we can look at the value of sq
(gdb) finish
Run till exit from #0 square (x=25) at square.c:29
main (argc=<optimized out>, argv=0x7fffffffeab8) at square.c:20
20 printf("%d squared is %d\n",numToSquare,squaredNum);
Value returned is $3 = 625
(gdb) l
15 // the first argument after the filename
16 int numToSquare = atoi(argv[1]);
17
18 int squaredNum = square(numToSquare);
19
20 printf("%d squared is %d\n",numToSquare,squaredNum);
21
22 return 0;
23 }
24
(gdb) n
25 squared is 625
Breakpoint 2, main (argc=<optimized out>, argv=0x7fffffffeab8) at square.c:23
23 }
(gdb) # we just called printf to print the result
(gdb) cont
Continuing.
[Inferior 1 (process 15818) exited normally]
(gdb)