CMSC 15400 - GDB lab - Wednesday, April 11

In this lab, you will complete a tutorial on the GDB debugger. Then you will complete an exercise where you will debug a simple linked list.
Email the results of this exercise to the TA; details are provided below.

References

As you go through the exercises today, reference the following for help on GDB:
We will also look at the tool objdump in this lab. You can find help on objdump here:

Discussion


Tutorial

Follow the steps of this tutorial.
You will use the following two programs: You are encouraged to discuss GDB commands and the steps of this Tutorial section with other students. You can find the C files used in the lab at /home/bomb154/maclabs/gdblab.tar. You can unpack these files to you current directory with the command:

   tar -xvf /home/bomb154/maclabs/gdblab.tar

You do not have to sumbit your work from this Tutorial section of the lab.

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 also set a breakpoint at the memory address of an instruction:

 break *<address>

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

The commands where and info stack are equivalent to backtrace.

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

Examining memory and registers

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) x/4i 0x8048422
   0x8048422 : mov $0x0,%eax
   0x8048427 : leave
   0x8048428 : ret
   0x8048429 : push %ebp

 
Here, /4i is an optional parameter, indicating that GDB should display 4 lines of machine instruction. Other formats are available, such as x/d for decimal, x/x for hex, and x/s for strings.

You can call the command print/x $reg to display the value of register $reg. Again, /x indicates that GDB should display the output in hex format.

To display the contents of every registers, use the command info registers.

CSPP51081: You can probably get by with skipping the next few topics. Don't forget the Exercise at the end. -Sonjia

Displaying machine instructions: disas

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.

Using objdump to examine binary files.

In addition to GDB, you can also use the program objdump to display a range of information about a binary file.

objdump -d disassembles a file (similar to disas in gdb).

objdump -t displays symbol table information


Exercise

You will now debug a C program that implements a simple linked list.

Note that there are two driver files included in the tar file for this lab: driver1.c and driver2.c. 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. However, you should try to find the bug on your own, and let others using the same driver to find it on their own as well.

Submitting this lab

Email your revised version of linkedlist.c as an attachment to Josh Grochow (joshuag@cs).
In the body of your email briefly answer the following questions:
  1. Did you use driver1.c or driver2.c?
  2. Which line of source code resulted in a segmentation fault? You may include the output of a GDB command.
  3. Which instruction resulted in this segmentation fault? Do not submit the memory address, instead display this instruction as assembly code. You may include the output of a GDB command.
  4. Where does the error occur in linkedlist.c? That is, which function is written incorrectly, and why is it incorrect?