CSPP 51081 Tutoria #4
Zip file for this tutorial: tut4.zip
The GDB debugger
References
As you go through the exercises today, reference the following for help on GDB:
Compiling for GDB: The -g flag
In order to debug a C program, you must compile with the '-g' option.
This option generates debugging information,
such as datatype and line number information, and stores this in the executable.
Starting GDB
After you have compiled a C source file with -g, you can run this program with GDB.
Use the command gdb <executable> at the command line.
- Start debugging ex1_count. The GDB prompt should appear:
% gdb ex1_count
GNU gdb 6.1-debian
...
(gdb)
-
Note that at any time, you can exit GDB with the command quit.
Running a program in GDB:
run
You can execute a program within GDB with the command run
- Execute ex1_count. The program should run normally.
(gdb) run
Starting program: /home/wax/cspp51081/tut4/ex1_count
Counting occurrences of 's' in string Jackson, Mississippi
Count: 20
run args
sets the arguments of your program (i.e., arguments the main function).
- Try this with Exercise 1:
(gdb) set args "Sonjia Wax"
(gdb) run
Starting program: /home/wax/html/cspp51081/tut4/ex1_count "Sonjia Wax"
Your input string is: Sonjia Wax
Counting occurrences of 's' in string Sonjia Wax
Count: 10
Program exited normally.
(gdb)
Of course, just running the program isn't enough to find our error.
We now look at some of the GDB commands used to examine the program as it executes.
Setting a breakpoint:
break
You can set a breakpoint so that GDB will pause execution at a certain line in the source code.
Use the command break, or the shortcut b, as follows:
break <function>
break <linenumber>
break <filename:function>
break <filename:linenumber>
You can display all active breakpoints with the command info break.
To delete a breakpoint, use one of the following:
delete <breakpoint number>
where number is obtained from info break, or
clear <...>
similar to break <...> above.
-
Set a breakpoint in the first line of the main function in ex1_count and execute this program:
(gdb) break main
Breakpoint 1 at 0x80483b4: file ex1_count.c, line 7.
(gdb) run
Starting program: /home/wax/cspp51081/tut4/ex1_count
Breakpoint 1, main () at ex1_count.c:7
7 char default_str[] = "Jackson, Mississippi";
(gdb)
You can add a breakpoint at time, that is, before or after you have called run.
We can use the command next, step, and continue to examine a program as it executes.
next executes one line of source code in the current function.
step is similar to next, but will step inside a function that is called on the current line.
next N and step N increment N lines, rather than just one line.
The list command displays source code around your most recent listing.
list <number> displays code around a particular line.
At any time, you can call continue to proceed automatically
to the next breakpoint or until the program terminates.
- Execute ex1_count line-by-line with the next and step
until you are within the function char_count.
Note that you need to use step when you reach the call to char_count in main:
int count = char_count('s',str);
- Call list to display the char_count function.
- Call continue so that the program terminates.
Displaying data:
print
and
watch
You can use the print command, or its shortcut p,
to display the value of a variable in the current function.
print is very flexible; you can dereference pointers, display addresses of variables, and index into arrays with the
*, &, and [] operators.
A watchpoint
is a breakpoint that stops execution whenever the value of a variable
or expression changes and displays the old and new values of that
expression.
You can set a watchpoint with the command watch <expr>
- Start ex1_count from the beginning (call run).
- Step until you reach the char_count function.
Or, you can also set a breakpoint at the char_count function.
- Use the print command to display the values of str,*str, and str[0].
- Set a watchpoint on the local variable count, and continue execution until the program terminates.
- Do you see why this char_count does not give the correct result?
Note that you can use the print command to examine the members of a struct:
(gdb) print *mylist
$2 = {first = 0x0, last = 0x0}
Examining the call stack
The
backtrace command can be called at any time in GDB, and shows which function is
associated with the current point of execution.
You can call backtrace
to see how the function got to where it is, that is, through what function calls. backtrace will display the current call stack, with one line per frame, where each frame effectively corresponds to a function call.
The commands where and info stack are equivalent to backtrace.
The commands
up and down
move "up" and "down" the call stack, that is, they will reset the current frame that is visible to you in GDB.
With no arguments,
frame
displays information about the current stack frame.
You will find that these commands are valuable for debugging segmentation faults, such as the one in Exercise 2.
You can use the command x to examine the contents of a
memory address.
For example, to display instructions at address 0x8048422, you can call:
(gdb) p &str2
$3 = (char (*)[256]) 0xbfb10484
(gdb) x/5c 0xbfb10484
0xbfb10484: 74 'J' 97 'a' 99 'c' 107 'k' 115 's'
Here, /5c is an optional parameter, indicating that GDB should display 5 characters ('c').
Other formats are available,
such as x/d for decimal, x/x for hex, and x/s for strings.
- Use the '&' operator to find the address of variable default_str in the function main.
- Now, use the x/s operator and format command to diplay the contents of this address as a null-terminated string.
Displaying machine instructions:
disas, info line
The command disas, or disas <function>, displays machine instructions for a given function (default is current frame).
To find the instruction address that corresponds to a line of source code, use info <line>.
To go in the reverse direction info *<address>
Stepping through and into a function, by instruction:
nexti, and stepi
We saw above how we can use next and step to step through
our program, line by line. The commands nexti and stepi are similar, but execute one instruction rather than one line our source code.
These commands can be useful for lines that contain several operations or function calls.
- Find the line in char_count where iter is incremented:
iter++;
- Set a breakpoint at in char_count, where iter is incremented
- Execute this line by instruction using the command stepi. Before you start, and after each instruction, display the value of this register and the variable iter. (You can also set a watchpoint to display these values)
ddd: a graphical interface to gdb
We can use ddd as a GUI front end for gdb.
Enter ddd at the command line to get started.
To load a file, do File|Open Program, or just file ex1_count at the prompt. (also a gdb command).
Here are some useful features of the ddd GUI:
- Source|Display Line Numbers
- Source|Display Arguments
- Source|Display Data
ifdef - conditional preprocessor directive
ex3_ifdef.c Text
We can use the -D option to gcc to define a macro with a string of "1", to ensure that an ifdef will pass.
tut4> gcc -DDEBUG ex3_ifdef.c
We often use ifdef to ensure the contents of a header file are only inluded once:
linkedlist.h Text
Multidimensional Arrays
C allows us to declare "arrays of arrays", that is, an array with more than one subscript.
ex4_marr.c Text
Note that the last array changes first, that is, temp[0][5] is adjacent to temp[0][6] but not temp[1][5]
GDB Exercise
You will now debug a C program that implements a simple linked list.
linkedlist.h Text
linkedlist.c Text
Note that there are two driver files included in the tar file for this lab:
driver1.c Text
driver2.c Text
Each uses the file linkedlist.c,
a dynamically-allocated linked list with two bugs. driver1.c will find one bug, and driver2.c will find the other.
- Select either driver1.c or driver2.c and use that driver file to complete this exercise.
- Compile linkedlist.c and driver1.c (or driver2.c):
gcc -g -Wall driver1.c linkedlist.c -o listtest
- Run listtest, and notice that this program ends with a segmentation fault.
- Using GDB, find the bug in this linked list, and fix the code so that the test passes:
% ./listtest
Test OK.
(If you get stuck, you can ask the TA for a hint).
You are encouraged to discuss GDB with other students.