CSE 490c/303, Autumn 2003 - Using GDB

Due: N/A

GDB is the GNU Debugger, and can be a useful tool for analyzing problems with your code.  This page gives a simple set of exercises to help you get acquianted with the debugger and it's functionality.  For more information consult the man page ('man gdb'), or view the online manual.

A First Pass

Login to attu.  Start by copying this file from the course directory to somewhere in your home directory:

/cse/courses/cse490c/03au/example.c

Take a brief look at the file - it's a simple C program.  Now, try executing the following commands:

gcc example.c
./a.out

The program crashes.  This is probably not a good sign - let's try taking a closer look at it:
Note: If the system doesn't say (core dumped), try running the following command: 'ulimit -c unlimited', then rerun a.out.

gdb a.out
core core.<tab><tab><enter>

GDB loads up the core file, which is actually the state of the memory of our program at the time it crashed.  We can ask GDB to tell us what functions were being called at the time of the crash using 'bt'

(gdb) bt
#0  0x0804847c in main ()
#1  0x42017589 in __libc_start_main () from /lib/i686/libc.so.6

It looks like we crashed in main() - lets try to see where exactly this happened:

(gdb) list
1       init.c: No such file or directory.
        in init.c	

This isn't very useful information. Why is gdb being so recalcitrant? Because we neglected to give it enough information. It turns out that gcc has an option to add debugging information into an executable - this will allow gdb to be more effective for us.

rm core.*
gcc -ggdb example.c
./a.out
Segmentation fault(core dumped)
gdb a.out
core core.<tab><tab><enter>

Now this is better - GDB has actually located the exact line in our source file which caused the crash! What can we do with this? Let's see what the variables look like:

(gdb) print x
$1 = (int *) 0x8049670
(gdb) print i
$2 = 3684
What did the code nearby look like?
(gdb) list
6               int *x;
7
8               x = (int*)malloc(10000);
9
10              for(i = 0; i < 10000; ++i){
11                      x[i] = i;
12              }
13

Oops. It looks like that malloc statement wasn't quite right.  Let's fix it - change malloc(10000) to malloc(sizeof(int) * 10000)
Now, recompile, then let's try running our program from inside of GDB:

gcc -ggdb example.c
gdb a.out
(gdb) break example.c:8
Breakpoint 1 at 0x8048476: file example.c, line 8.
(gdb) run
Starting program: /homes/iws/rjpower/temp/a.out

Breakpoint 1, main (argc=1, argv=0xbffff454) at example.c:8
8               x = (int*)malloc(sizeof(int) * 10000);
(gdb) step
10              for(i = 0; i < 10000; ++i){
(gdb) step
11                      x[i] = i;
(gdb) step
10              for(i = 0; i < 10000; ++i){
(gdb) step
11                      x[i] = i;
(gdb)

What have we done? We've set a breakpoint to tell GDB to stop the execution of our program when it reaches a certain point in our file - that place is example.c:8 - the 8th line of example.c. Once it reaches that point, we tell it to 'step' - run the program one step at a time for us. Since this will take a while with a loop running 10000 times, let's continue on:

(gdb) break example.c:14
Breakpoint 2 at 0x80484b8: file example.c, line 14.
(gdb) continue
Continuing.

Breakpoint 2, main (argc=1, argv=0xbffff454) at example.c:14
14              scanf("%d", k);
(gdb)step
<type a number here>
15              tester(x);
(gdb) continue

Okay - it seems to work now. Let's try running it outside of the debugger:

./a.out
Segmentation fault(core dumped)

What's going on? It worked in the debugger...

Exercises (don't turn these in)