TWiki> CS361fall13 Web>Homework6 (revision 2)EditAttach

Homework 6 - Build your own debugger

In this homework we'll be building a stripped down version of gdb. The template solution comes with a library for reading debugging symbols (dwarf_symbol_reader) and for processing user input (debugger_interface), allowing you to focus on developing the features.

Initial Setup

You'll need a few libraries first. Run the following command before trying to compile the template...

    sudo apt-get install libelf-dev libdwarf-dev dwarfdump libncurses5-dev 

dwarfdump is a program that displays the dwarf debugging symbols for a program. It may be helpful to you for this assignment.

API Info

You'll have to use the ptrace API for this assignment along with a couple of libraries that I wrote. Familiarize yourself with these things BEFORE starting the assignment! I suggest you peek at the .c and .h files also, just to get a flavor of what is going on.

Debugger Interface (debugger_interface.h)

This module handles the user input to the debugger. Each command from the user has a command type and a value associated with it. For instance, if the user types "b 7" then the command type is CMD_TYPE_BREAKPOINT and the value is the line number where we want to set the breakpoint.

Values can be strings (for instance the name of a variable for printing) or integers so we use a union type to represent it. The union type in the user_command struct is called value. Below is an example of how to access the line_number from a user_command.

      user_command * cmd = debugger_interface_get_cmd();       //now handle the input       switch(cmd->command_type){           case CMD_TYPE_BREAKPOINT:            set_breakpoint_from_line_number(cmd->value.line_number);            break;           case CMD_TYPE_PRINT:            printf("printing not implemented yet\n");            break;           case CMD_TYPE_CONTINUE:            //tell the child to keep going                     break;         } 

dwarf_symbol_reader.h

This module allows you to get info about the program that you are debugging (assuming that program was compiled with dwarf debugging symbols). This includes such info as function names, function starting and ending addresses, variable names and locations, etc... The dwarf_symbol_reader.h file has lots of comments so make sure to take a look in there. For all of the parts of the assignment you will need to utilize this library!.

Dwarf considers each object file a "compilation unit". For this assignment we'll only have a single compilation unit because the programs we will be using are very simple. Many of the functions in dwarf_symbol_reader.h take a compilation unit, so you'll want to grab the compilation unit at the beginning of the debugging process using the function dwarf_get_compilation_unit.

A die (debugging information entries) contains the debugging information for a given entity in a program. So a function would have a die, a variable would have a die, and so forth. In fact, the whole compilation unit also has a die and is available in the struct dwarf_compilation_unit type as root_die. The dies are organized into a tree with the compilation unit as a root. So, if variable x is in function fun1, then x's die is a child of fun1 . Most of the functions in dwarf_symbol_reader.h take a die as a parameter.

One of the main things that you can do with these functions is iterate through a bunch of dies. So lets say you wanted to loop through all the function dies in your program. You would do the following

    //start with the first child of the root die     Dwarf_Die func_die =  dwarf_get_next_function(compilation_unit->root_die, compilation_unit);      while(func_die){         //do something with the function die         //...         //now get the next one         func_die =  dwarf_get_next_function(func_die, compilation_unit);     } 

There are similar iterator functions available for variables.

Using Ptrace

The Ptrace library allows a debugging program to have total control over the debuggee. Using Ptrace, our debugger (via the operating system) can modify a program's instructions, read a program's memory, stop it, start it, single step it, etc... The man page for Ptrace is great and is linked below in the references. You will need to make at least 1 Ptrace call for every part of this homework.

a. Setting a breakpoint

The first thing you will need to do is set a breakpoint and have the program stop at that line. To do this you will have to modify the right instruction by replacing the low order byte with an int3 (0xCC) op code. Make sure to store away the old instruction so that you can put it back once the breakpoint has been hit. The users interaction with this functionality should look like this...

    361db>> b 7     breakpoint 1 set at line 7     361db>> c     continuing...     breakpoint 1 hit     361db>> 

b. Where am I?

When debugging it is always helpful to know where you are in a certain file. For part 1 you will print out the line you are currently on and the file name. (HINT: use the instruction pointer from ptrace to figure out the line). Here is the intended output...

    361db>> where     line 1 in prog1.c 

c. Persistent breakpoints

When you hit a breakpoint you must take the original instruction and put it back, thus removing your breakpoint. For part b we now make our breakpoints persistent so that they stick around. (Hint: take a look at single stepping with ptrace). The user should be able to hit the same breakpoint multiple times without having to set it more than once.

d. Multiple breakpoints

Its not very fun for the user to only be able to set one breakpoint at a time. Now allow the user to have multiple breakpoints set concurrently. Here's an example of the expected output.

    361db>> b 7     breakpoint 1 set at line 7     361db>> b 8     breakpoint 2 set at line 8     361db>>c     hit breakpoint 1     361db>>c     hit breakpoint 2 

e. Printing Variables

Being able to inspect the value of a variable is an important part of debugging. For part e we will now implement the printing of variables. The p command will take two arguments: the first is the format specifier (/d for integer in decimal, /c for character, etc...) and the second is the variable name. I will only test that your program can print integers and characters. Here's the expected output.

    361db>> b 7     breakpoint 1 set at line 7     361db>> p /d x     101     361db>> c 

f. Printing out strings

If you can print out a single value it should be too hard to also print out a string of characters. For three points bonus, modify your program to do just that.

    361db>> p /s trueStr     "CS 361 is so much fun!"     361db>> c 

References

1.) Take a look at this blog entry...it should take you a long way How a Debugger Works

2.) The Ptrace man page

3.) An in depth look into dwarf Debugging formats DWARF and STAB

4.) Walk-through of the template code

5.) Debugging Lecture

Edit | Attach | Print version | History: r4 < r3 < r2 < r1 | Backlinks | Raw View | Raw edit | More topic actions...
Topic revision: r2 - 2013-10-08 - 12:23:58 - Main.tmerri4
 
Copyright 2016 The Board of Trustees
of the University of Illinois.webmaster@cs.uic.edu
WISEST
Helping Women Faculty Advance
Funded by NSF