The gdb
utility is the debugger that comes with the GNU compilers
such as gcc
and g++
. It allows you to either step
line-by-line through your code or to examine a special file called a coredump.
In lab today, we will examine a coredump file caused by a bad pointer reference.
A coredump file is a special file generated when your code crashes with an error such as a Segmentation fault. It contains enough information about the state of the program that you can usually use a coredump file to determine why the program crashed while running. This is particularly useful when your program only crashes under certain circumstances.
By default on Sleipnir, a coredump file will NOT be generated when your code crashes. You must turn on the generation of a coredump file with the following command AFTER you have logged in to Sleipnir:
ulimit -c unlimitedFor this lab, we will be using a simple example code, lab8_handout.cpp, which contains a pointer version of a
getInput
function for a single integer. The
code will generate a coredump because we have forgotten to set the pointer to
the variable num
before we call getInput
. So the pointer
is still pointing to NULL when we try to set the value, which triggers a
Segmentation fault.
To use gdb
, you have to compile with debugging info turned on.
To do this, you give the -g
option to g++
to turn on debugging info. So compile and run the handout with the following
commands:
g++ -g -o lab8 lab8_handout.cpp ./lab8When you run lab8, you should see
Segmentation fault (core dumped)
after entering the integer. If you do not see (core dumped)
rerun the ulimit
command from above and then rerun lab8. Once you
have the coredump file, start gdb
with the following command:
gdb lab8 coreThe first argument to gdb is the executable's name (lab8) and the second argument is the coredump's filename (core is the default filename). You will now be at the prompt for gdb. It should look something like the following:
GNU gdb 6.8-debian Copyright (C) 2008 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"... warning: Can't read pathname for load map: Input/output error. Reading symbols from /usr/lib/libstdc++.so.6...done. Loaded symbols for /usr/lib/libstdc++.so.6 Reading symbols from /lib/libm.so.6...done. Loaded symbols for /lib/libm.so.6 Reading symbols from /lib/libgcc_s.so.1...done. Loaded symbols for /lib/libgcc_s.so.1 Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux-x86-64.so.2...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `./lab8'. Program terminated with signal 11, Segmentation fault. [New process 1261] #0 0x00007f82ec506fd9 in std::istream::operator>> () from /usr/lib/libstdc++.so.6 (gdb)The line
(gdb)
is the gdb prompt. When at this prompt, you can
issue various gdb commands to see the state of your program. Let's first try
the backtrace
command, which will show all the function calls
that led up to the segmentation fault.
To give the backtrace command, type the following command at the gdb prompt:
btThis should show you something like the following:
(gdb) bt #0 0x00007f82ec506fd9 in std::istream::operator>> () from /usr/lib/libstdc++.so.6 #1 0x0000000000400997 in getInput (ptr=0x0) at lab8_handout.cpp:31 #2 0x00000000004009b2 in main () at lab8_handout.cpp:19The first field (#0, #1 and #2) tells you what line and function generated the error. The numbers are referred to as frames in gdb. So we see the error occurred in the input operator (>>) in frame #0. This was called by line 31 in the getInput function in frame #1. That line in frame #1 was called by line 19 in main in frame #2.
We can select one of these frames to look at further. Usually it's not helpful to look at frames for the C++ libraries, so we can skip frame #0. To look at frame #1, give the following command at the gdb prompt:
frame 1This will switch us to the scope of getInput. We can then example getInput's arguments and local variables (if it has any). getInput has one argument called ptr. To print the current value of ptr, type the following command:
print ptrThis will print out that ptr is currently 0x0, which is the NULL pointer. We then know that ptr was not set appropriately. This could be because we passed the wrong pointer from main (particularly in a program with many pointers) or because we forgot to set the pointer in main.
Our next step is to see the state of the pointers in main. main is in frame 2, so to switch to that scope, type the command:
frame 2To look at all the variables local to main at once, we can type the following command (this command does not work for arguments, just for variables declared inside the current scope):
info localsIn the output of info locals, you should see that the address for
p
is 0x0, which tells us that p
is still a NULL
pointer. This is why the code crashed. You cannot set values for the NULL
pointer. Looking back at the code, we see that p
was initialized
to NULL at the top of main (you should get in the habit of doing this with
all pointers you declare) and, as the comments indicate, p
was
never set to the address of num
.
Before continuing on to the rest of the assignment, exit gdb by giving the following command:
quit
Email me your completed lab8.cpp file.