Showing posts with label Debugging with GDB. Show all posts
Showing posts with label Debugging with GDB. Show all posts

Thursday, August 30, 2007

Debugging with GDB

Debugging with GDB: Child's Play!

Check out the basics of the GNU Debugger in the first of two articles on GDB, an open source debugging tool.

For simple programs, debugging without a debugger might be possible by walking through the source code. To do that, you just need to give the debug print statements. But it may not be possible to effectively and efficiently crack problems by doing this for complex programs and systems. This is addressed by the use of debuggers. The debugger is one of the most important tools of any development system.

GDB (GNU Debugger) is one of the most popular open source debugging tools available. The GNU compiler, Emacs Editor and other utilities, work very closely with the GNU debugger. GDB has a command line interface. It supports object file formats like ELF, S-record and many others, and languages like C, C++, etc. In the first of this two-article series, we will focus on the basics of GDB, and in the second part we will cover the advanced features of GDB.

Installation
GDB is available with various Linux distribution CDs. You can obtain the latest binary GDB images from [http://ftp.gnu.org/gnu/gdb/], or if you want the latest GDB RPM, you can find it at [http://rpmfind.net] and install it if needed.

Getting started with GDB

GDB provides a command line interface with a lot of commands to cater to the various needs of debugging, which we will be covering in detail in the following sections. For instance, to debug a C executable you can enter (where mybin is the executable):

# gdb mybin      

Alternatively, you could invoke gdb and then use the file command.

# gdb

(gdb) file mybin
Note that you need to use the gcc -g option to compile your C program so that the debugging information is stored in your executable, which aids in debugging. For instance, let's compile mybin.c with and without debugging information, and see the difference.
% cat mybin.c

#include "stdio.h"

int main(int argc, char** argv) {

printf("test");

return 0;

}
Compiling C programs in debugging mode 
 
% gcc -g mybin.c -o mybin    // here –g opetion will set the program to debug mode
  
$ gdb

(gdb) file mybin

Reading symbols from mybin...done.

(gdb) break 1

Breakpoint 1 at 0x8048460: file mybin.c, line 1.

(gdb) run

Starting program: /home/sekarbc/mybin
Breakpoint 1, main (argc=134513760, argv=0x1) at mybin.c:2

warning: Source file is more recent than executable.
2       int main(int argc, char** argv) {


(gdb) next

main (argc=1, argv=0xbffff8d4) at mybin.c:3

3 printf("test");

(gdb) next

4 return 0;

(gdb) next

5 }

(gdb) next

test

Program exited normally.

Clearly, from the above example, you could see how the gcc --g option helps in creating break points, in walking through the code step by step, and in making use of the debugging symbols that the gcc --g option adds to the executable.

$ gcc mybin.c -o mybin

$ gdb

(gdb) file mybin

Reading symbols from mybin...done.

(gdb) break 1

No line 1 in file "init.c".

(gdb) run

Starting program: /home/sekarbc/mybin

test

Program exited normally.

From the above example you can see that without the gcc --g option, debugging is worse.

GDB commands

When gdb starts, your program is not actually running. It won't run until you tell gdb how to run it. Whenever the prompt appears, you have all the commands on the quick reference sheet available to you.

· run command-line-arguments

Starts your program as if you had typed

a.out command-line arguments

or you can do the following

a.out <>  

to pipe a file as standard input to your program

· break place

Creates a breakpoint; the program will halt when it gets there. The most common breakpoints are at the beginnings of functions, as in

(gdb) break Traverse



Breakpoint 2 at 0x2290: file main.c, line 20

The command break main stops at the beginning of execution. You can also set breakpoints at a particular line in a source file:

(gdb) break 20



Breakpoint 2 at 0x2290: file main.c, line 20

When you run your program and it hits a breakpoint, you'll get a message and prompt like this.

Breakpoint 1, Traverse(head=0x6110, NumNodes=4)



  at main.c:16



(gdb)

In Emacs, you may also use C-c C-b to set a breakpoint at the current point in the program ( the line you have stepped to, for example) or you can move to the line at which you wish to set a breakpoint, and type C-x SPC (Control-X followed by a space).

· delete N

Removes breakpoint number N. Leave off N to remove all breakpoints. info break gives info about each breakpoint

· help command

Provides a brief description of a GDB command or topic. Plain help lists the possible topics

· step

Executes the current line of the program and stops on the next statement to be executed

· next

Like step, however, if the current line of the program contains a function call, it executes the function and stops at the next line.

· step would put you at the beginning of the function

· finish

Keeps doing nexts, without stepping, until reaching the end of the current function

· Continue

Continues regular execution of the program until a breakpoint is hit or the program stops

· file filename

Reloads the debugging info. You need to do this if you are debugging under emacs, and you recompile in a different executable. You MUST tell gdb to load the new file, or else you will keep trying to debug the old program, and this will drive you crazy

· where

Produces a backtrace - the chain of function calls that brought the program to its current place. The command backtrace is equivalent

· print E

prints the value of E in the current framein the program, where E is a C expression (usually just a variable). display is similar, except every time you execute a next or step, it will print out the expression based on the new variable values

· quit

Leave GDB. If you are running gdb under emacs,

C-x 0 

will get you just your code back

The goal of gdb is to give you enough info to pinpoint where your program crashes, and find the bad pointer that is the cause of the problem. Although the actual error probably occurred much earlier in the program, figuring out which variable is causing trouble is a big step in the right direction. Before you seek help from a TA or preceptor, you should try to figure out where your error is occurring

Passing arguments

GDB allows you to pass arguments to the program that is being debugged. You can specify the arguments in the run command when you are in gdb prompt.

For instance, take argtest.c

$ gcc -g argtest.c -o argtest

$ gdb argtest

(gdb) run

Starting program: /home/sekarbc/argtest
You have to use two command line arguments
Program exited with code 0377.

(gdb) run abc def

Starting program: /home/sekarbc/argtest abc def

The first argument is : abc

The second argument is : def
Program exited with code 035.

(gdb)

An alternate method is to use set args command when you are in gdb prompt.

(gdb) file argtest

(gdb) set args abc def

(gdb) run

Starting program: /home/sekarbc/a.out abc def

The first argument is : abc

The second argument is : def
Program exited with code 035.

Working with break points

A break point is a place in the source code file where we temporarily want to stop execution of the program being debugged. Break points can be placed by using the break command. But remember that the program needs to be compiled with the -g option for break points to work. You could use the list keyword to first find out the line number at which to issue the break.

$ gdb sum

(gdb) list

1
#include "stdio.h"

2
int main ()

3
{

4
int num1, num2, total ;

5
printf("Enter first number : ");

6
scanf("%d", &num1);

7
printf("Enter second number : ");

8
scanf("%d", &num2);

9
total = num1 + num2;

10
printf("\nThe sum is : %d\n", total);

To issue a break point at Line 5, we issue:

# (gdb) break sum.c:5

Breakpoint 1 at 0x8048496: file sum.c, line 5.

An alternate way is to set the break point using the function name.

# (gdb) break main

Note: breakpoint 1 also set at pc 0x8048496.

Breakpoint 2 at 0x8048496: file sum.c, line 5.

When you type run in the gdb prompt, instead of the program executing fully, the execution stops in the break point.

# (gdb) run

Starting program: /home/sekarbc/sum
Breakpoint 1, main () at sum.c:5

5
printf("Enter first number : ");

You can find out the information about the break points by typing:

# (gdb) info break

Num Type
Disp Enb Address What

1
breakpoint keep y 0x08048496 in main at sum.c:5

breakpoint already hit 1 time

2
breakpoint keep y 0x08048496 in main at sum.c:5

breakpoint already hit 1 time

Another step before 'continue-ing' Once you have set a break point, it allows you to walk through to the next instruction. Suppose the next instruction is a function sum, step takes execution control through inside the sum function. Continue allows you to continue with the execution of the program. If there is another break point, then it takes you to the break point.

# (gdb) run sum

Starting program: /home/sekarbc/sum sum

Breakpoint 1, main () at sum.c:3

3 {
(gdb) continue

Continuing.
Breakpoint 2, main () at sum.c:6

6 scanf("%d", &num1);
(gdb) run

Starting program: /home/sekarbc/sum sum
Breakpoint 1, main () at sum.c:3

3
{

(gdb) next

main () at sum.c:5

5
printf("Enter first number : ");

(gdb) next
Breakpoint 2, main () at sum.c:6

6 scanf("%d", &num1);
(gdb) run sum  
 (gdb) step

sum (num1=1, num2=2) at sum.c:5

5
return num1+num2;

Examining variables

GDB allows us to display program and environment variables during program execution. We can do this using the print command every time or we can get the values displayed automatically using display command.

(gdb) file sum

A program is being debugged already.
Kill it? (y or n) y
Load new symbol table from "sum"? (y or n) y

Reading symbols from sum...done.

(gdb) break 3

Breakpoint 2 at 0x8048490: file sum.c, line 3.

(gdb) run

Starting program: /home/sekarbc/sum sum
Breakpoint 1, main () at sum.c:11

11
printf("Enter first number : ");

(gdb) n

12
scanf("%d", &num1);

(gdb) print num1

$1 = 134518456

(gdb) n

Enter first number : 5

13
printf("Enter second number : ");

(gdb) print num1

$2 = 5
(gdb) n
The sum is: 20

17
}

3: total = 20

2: num2 = 15

1: num1 = 5

(gdb) run

Starting program: /home/sekarbc/sum
Breakpoint 1, main () at sum.c:11

11
printf("Enter first number : ");

(gdb) display num1

1: num1 = 134518456

(gdb) display num2

2: num2 = 134518236

(gdb) display total

3: total = 134513777

To cap it all

We hope that covering the basics of GDB will help you to sail through the entire process smoothly. This article should help you understand the advanced debugging techniques using GDB, which would be the focus in the next and concluding part of the series.

By: B.C. Sekar and Prakash Varandhani; HCL Technologies -- networking products division.