SPO Lab3 Single Steppin’ With GDB

Written by Hunter Jansen on September 22, 2014

The third lab for my SPO600 course involves investigating a single specific aspect of GDB, and presenting my findings in a short, informative session to my fellow classmates. I’ve used this opportunity to cover how to step through a program step by step and also view the values in the registers

I also used this opportunity to tease/create an early alpha presentation using the presentation platform I’m working on: Show Me The Thing, but that’s for a different post

Lab Description

The lab can be found here.

The Slides

The slides are available on google drive here.

I’ve also made them available on calmlycoding @ calmlycoding.com/spo-debug/#solo

Let’s start Debugging

Alright, so in order to begin debugging with the Gnu Debugger (GDB) we need to compile it using the the -g flag.

For our examples today, we’re going to use the super simple step.c program below:

#include <stdio.h>

void print_string(int num){
    printf("Printing: %d\n", num);
}

void main(){
    int i;
    for(i=0; i<10; i++){
        print_string(i);
        printf("After");
    }
}

All this does is loops 10 times, calling a separate function to print out ‘Printing: ‘ from 0 to 9. Basic, but it’ll work for our needs.

We’ll compile it using:

    gcc -g step.c
    

You’ll still receive your expected a.out file from this which you can run as normal, but you’ll also be able to run it using the gdb command to begin debugging and stepping through. To begin using GDB you simply need to call gdb with the desired program. So for our example we use:

    gdb a.out
    

You’ll know that you’re running with gdb because your command line will have a (gdb) now.

Commands

So, obviously there’s a bunch of commands and stuff you can do with gdb, but I’m just covering the basic functionality here. The most basic thing you can do is use the run command to invoke the program as though you’d called ./a.out normally.

    run
    

This would run through the program normally, and provide us with the ‘Printing: 0’ - ‘Printing: 9’. It’s also worth mentioning that if you’re running a program that expects arguments to be passed in, you can do this by providing those arguments following the run command:

    run arg1 arg2
    

Super simple so far - but then again we haven’t really done anything…

###Breaking Points One of the key aspects of any debugger is the ability to add break points to lines of code that you’d like the program to stop on to check everything out. Luckily, adding a breakpoint to gdb is simple.

To add a breakpoint to a specific line of code we just use the following command in gdb:

    break step.c:5
    

In this example, we’re adding a break point to the 5th line in the source. More often then not, you’ll commonly just want to add a breakpoint to a function, pausing when the function is invoked from any source. To do this we call break followed by the desired function name. So if we wanted to add a break point to the print_string function:

    break print_string
    

Following adding a break point the program will stop at that point when you run it. So for our previous example we’d get the following output after issuing the ‘run’ command:

    Breakpoint 1, print_string (num=0) at step.c:4

###Stepping Through Another key bit of functionality when it comes to debuggers is the ability to step through a program one line at a time. There are two different commands when it comes to walking through with GDB - step and next. While similar, they are indeed different. Step will enter a function call, whereas next will skip over it. But what does that mean?

Consider the following snippet:

1    for(i=0; i<10; i++){
2        print_string(i);
3        printf("After");
4    }
    

If you were to step on line 2, you’d find yourself with a break on the first line in the print_string function - however if you use the next command, it’ll execute the print_string function and then break on the following line.

To step in GDB you you simply run the step command in gdb

    step

or, if you want to step through the next machine instruction as opposed to the next line of source you can use:

    stepi

Similary, to use the next command you run next in gdb

    next

or, if you want to step through the next machine instruction as opposed to the next line of source using next::

    nexti

###Checking register values Cool, so now we can set break points and step through instructions and what not. While that’s all fun it’s not really useful without one last part - checking the values of variables. There’s really no point in stepping through a program without being able to see the values of the variables.

As with everything else in this walkthrough, checking variable values is pretty simple. The command to check a variable by name is ‘print’.

So, for example if we were stopped in our print_string function and wanted to check the current value of the num variable in gdb we’d run:

    print num

This would give us the output along the lines of:

    $1 = 4

In this case the ‘$1’ is the amount of times I’ve printed variable values, this auto increments as you print more variables. And since I printed this on my fourth execution of the print_string function, the value of num is 4.

Another value you might want to check on is the values in registers/ a specific register. The command you use to do this is ‘info’. To view all the registers and their values you can enter:

    info reg

or:

    info registers

If you know the specific register whose value you like to check on you can call the info reg command with the name of the register:

    info reg rax

provides the output:

    rax 0xc 12

That’s about all the points that I’ll be touching on this time, and that should be plenty to get you up and running with GDB to help you with debugging!

Until Next time -Hunter