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.

Running a program in GDB: run

You can execute a program within GDB with the command run run args sets the arguments of your program (i.e., arguments the main function).

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. You can add a breakpoint at time, that is, before or after you have called run.

Stepping through and into a function, by line: next, step, and continue

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.

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>
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.


Examining memory

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.

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.

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:

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.
You are encouraged to discuss GDB with other students.