Guide Debugging with GDB

Status
Not open for further replies.
Debugging with GDB


GDB is a useful, easy to use debugging tool. Using GDB you can debug programs written in different programming languages like C, C++, Ada etc. and compiled for different architectures like VxWorks, Power PC etc. In this article, we will discuss basic GDB commands and a real-life example which will help you getting started with GDB.

Debugging is a part and parcel of a programmer's life. The purpose of a debugger is to allow you to peek inside a program while it executes or the moment it crashed. Using a debugger you can find the exact point in the code where the program is misbehaving, and then fix it appropriately. Debugging a piece of code can be real challenging, especially if it has been written by somebody else and spans multiple source files. Various debugging tools are available for different languages and different platforms.

In this article, we will discuss a very powerful command line based tool: GDB.

Introduction

GDB is free software, protected by the GNU General Public License (GPL). GDB or The GNU Source-Level Debugger can be used to debug programs written in C, C++, Fortran, Objective-C and many other languages. GDB can do the following things to help you catch bugs in your programs:

  • ·Start your program, specifying anything that might affect its behavior.
  • ·Make your program stop at specified locations or specified conditions.
  • ·Examine what has happened, when your program stopped.
  • ·Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.


Playing with GDB

To start GDB, simply fire up a Linux terminal and type 'gdb'. Once started GDB reads commands from the terminal until you exit from it.

The most usual way to start GDB is:

$ gdb program


where program is an executable file.

If you want to debug a running process, then type:

$ gdb program pid
where pid is the process-id of the running process.

To display help and all available options and brief description of their use, type:

$ gdb --help or $ gdb -h


If you need to execute shell commands during your debugging session, there is no need to quit GDB; you can just use the shell command:

(gdb) shell command-string


For e.g. (gdb) shell ls

This command will display all the files in the current working directory within the GDB environment.

Here, (gdb) is the GDB prompt.

For running your program, simply type 'run':

(gdb) run
For quitting GDB, type 'quit':

(gdb) quit
Logging GDB's output

You can save the output of GDB commands to a file. Several commands are available to control GDB's logging:

Enable logging.

(gdb) set logging on


Disable logging.

(gdb) set logging off


Change the name of the current logfile.

(gdb) set logging file <filename>


Show the current values of logging settings.

(gdb) show logging


Getting help in GDB

GDB has a very comprehensive and easy to use help:

(gdb) help
You can use help with no arguments to display a short list of named classes of commands.

(gdb) help class
Using one of the help classes as an argument, you can get a list of individual commands in that class.

(gdb) help command
With a command name as an argument, GDB displays a short summary about the command.

In addition to help, you can use the GDB commands ‘show’ and ‘info’ to inquire about the state of GDB or the program being debugged.

(gdb) info
This command describes the state of your program. For example, you can list the breakpoints you have set with info breakpoints. You can get a complete list of info sub-commands with help info.

(gdb) show
This command describes the state of GDB itself. For example, you can list the history of commands you have typed using show commands. You can get a complete list of show sub-commands with help show.

Getting Debugging Information

In order to debug a program effectively, you need to generate debugging information when the program is compiled. This debugging information is stored in the object file.

To generate debugging information, specify the '-g' option when the program is compiled. For example:

$ gcc -g -o <output-file> <source-file>


Breakpoints, watchpoints and catchpoints

A breakpoint makes your program stop whenever a certain point in the program is reached. You can set breakpoints with the break command and its variants, to specify the place where your program should stop by line number, function name or exact address in the program.

A watchpoint is a special breakpoint that stops your program when the value of an expression changes.

A catchpoint is another special breakpoint that stops your program when a certain kind of event occurs, such as loading of a library.

GDB assigns a number to each breakpoint, watchpoint, or catchpoint when you create it. Each breakpoint may be enabled or disabled. A disabled breakpoint has no effect on your program until enabled. There are several ways of setting a breakpoint:

(gdb) break line-number
Sets a breakpoint at the specified line number in the current source file.

(gdb) break function
Sets a breakpoint at entry to the function function

(gdb) break filename:line-number
Sets a breakpoint at the specified line-number in the source file filename.

(gdb) break filename:function
Sets a breakpoint at entry to the function function found in file filename.

(gdb) break *address
Sets a breakpoint at the specified address.

(gdb) break ... if cond
Sets a breakpoint with condition cond; evaluate the expression cond each time the breakpoint is reached, and stop only if cond evaluates as true.

Note: To check the status of user-set breakpoints, type info breakpoints.

To delete a breakpoint, use the delete or clear commands.


Stepping and Continuing

Stepping
means executing one more 'step' of your program, where 'step' can be a line of source code or a machine instruction. Continuing means resuming program execution until your program completes normally. When your program execution stops due to a breakpoint, you can either step one instruction at a time or continue the program execution normally.

(gdb) step
Continue running the program until control reaches a different source line, then stop it and return control to GDB.

(gdb) continue
Continue program being debugged, after signal or breakpoint.

(gdb) next
Step program, proceeding through subroutine calls. This is similar to step, but function calls that appear within the line of code are executed without stopping.

Stacks and Backtraces

Stacks

When your program stops, either due to a breakpoint or a signal, the first thing you need to know is where exactly it stopped and how it got there. Each time your program performs a function call; information about the call is generated, which includes the location of the call in your program, the arguments of the call and the local variables of the function being called. The information is saved in a block of data called a stack frame. The stack frames are allocated in a region of memory called the call stack.

GDB offers several commands for examining the stack when your program stops.

Backtraces

A backtrace is a summary of how your program got where it is. Each line in the backtrace shows the frame number and the function name. The backtrace also shows the source file name and line number, as well as the arguments to the function.

Printing source lines

To print source lines from a file, use the list command. By default, ten lines are printed. Here are the forms of most commonly used list commands:

(gdb) list linenum
Print lines centered around line number linenum in the current source file.

(gdb) list function
Print lines centered around the beginning of function function.

(gdb) show listsize
Display the number of lines that list prints.

(gdb) set listsize count
Make the list display count source lines.

Note:
For more options about the list command, type:

(gdb) help list


Printing and Examining Data

To examine data in your program you can use the print and the x command. It evaluates and prints the value of an expression you have typed.



(gdb) print expr


Evaluate and print the value of the specified expression expr.

(gdb) print
If you omit expr, last printed value is displayed again.

(gdb) set print address off
Do not print addresses when displaying their contents.

(gdb) show print address
Show whether or not addresses are to be printed.

You can use the command x (for examine) to examine memory in any of the several formats:

(gdb) x /fmt addr
Use the x command to examine memory using various formats (/fmt).

Tip:
If you want to print the value of an expression frequently, you might want to add it to the automatic display list so that GDB prints its value each time the program execution stops.

(gdb) display
Display the current values of the expressions on the list.



(gdb) display expr


Add the expression expr to the list of expressions to be displayed each time your program stops.

[BREAK=A Real Life Example & Summary]

A real-life example

Consider the following example which compares the length of two strings and displays which one is longer (Figure1 and Figure2):

___________


_________Figure1 _________________________________
Figure2



Compile the program as follows:

$ gcc -Wall -g -o compare compare.c


Now, run the program:

$ ./compare
String str1=linux is longer

Though the program executed successfully, the output is not what we expected. The output should have been as follows:

String str2=linuxforyou is longer

Let’s debug the program using GDB.

$ gdb ./compare
GNU gdb Red Hat Linux (6.1post-1.20040607.43rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

# Enable logging

(gdb) set logging on
Copying output to gdb.txt.

(gdb) set listsize 15
(gdb) list
1 /*

2 * Program to compare two strings

3 * Filename: compare.c

4 */

5 #include "compare.h"

6 void compare(char*, char*);

7

8 int main()

9 {

10 char *str1 = "linux";

11 char *str2 = "linuxforyou";

12 compare(str1, str2);

13 return 0;

14 }

15

(gdb) run
Starting program: /home/raman/gdb_progs/compare

Reading symbols from shared object read from target memory...done.

Loaded system supplied DSO at 0xffffe000

String str1=linux is longer

Program exited normally.

# Set a breakpoint at the string compare function

(gdb) break compare
Breakpoint 1 at 0x804847a: file compare.h, line 11.

(gdb) info breakpoints
Num Type Disp Enb Address What

1 breakpoint keep y 0x0804847a in compare at compare.h:11

(gdb) run
warning: cannot close "shared object read from target memory": File in wrong format

Starting program: /home/raman/gdb_progs/compare

Reading symbols from shared object read from target memory...done.

Loaded system supplied DSO at 0xffffe000

Breakpoint 1, compare (str1=0x804863c "linux", str2=0x8048642 "linuxforyou")

at compare.h:11

11 len1 = strlen(str2);

# If you don't want to display addresses, then type:

(gdb) set print address off
# Automate the display of str1, str2, len1, len2

(gdb) display str1
1: str1 = "linux"

(gdb) display str2
2: str2 = "linuxforyou"

(gdb) display len1
3: len1 = 134518588

(gdb) display len2
4: len2 = 134513936

# Step to the next line

(gdb) next
12 len2 = strlen(str1);

4: len2 = 134513936

3: len1 = 11

2: str2 = "linuxforyou"

1: str1 = "linux"

(gdb) next
13 if(len1 > len2)

4: len2 = 5

3: len1 = 11

2: str2 = "linuxforyou"

1: str1 = "linux"

From the above values we can notice that the values of len1 and len2 are incorrect, so we can set them to correct values as follows:

(gdb) print len1=strlen(str1)
$1 = 5

(gdb) print len2=strlen(str2)
$2 = 11

(gdb) next
16 printf("String str2=%s is longer\n", str2);

4: len2 = 11

3: len1 = 5

2: str2 = "linuxforyou"

1: str1 = "linux"

(gdb) continue

Continuing.

String str2=linuxforyou is longer

Program exited normally.

Bingo!!! This time the output is correct.

So, by debugging the program using GDB we found where the problem was.

The problem can now be fixed by making appropriate changes in the source file.

# Quit GDB as follows:

(gdb) quit


Summary

In this article we discussed about some of the commands which can help you getting started in GDB and debug programs spanning multiple source files. Debugging can be a nightmare for new programmers on *nix platforms. GDB is a very powerful and easy to use tool if you have the source code of the application. Using GDB along with other tools like strace, purify etc. can really make a programmer's life easy.

Happy Debugging!!!

Note: This article includes references from the GDB Manual and is licensed under the GNU Free Documentation License. Visit GNU Free Documentation License - GNU Project - Free Software Foundation (FSF) for more details.

 
  • Like
Reactions: 4 people
No buddy I used to use it last year and probably will get back to it sometime in next couple of months. The thing is very few people get into c nowadays I think. Ive moved over to python :) for most of my needs.

And a nice tut there. Thanks, im sure i will get back here when I start my upgrade work. but most of the time I use Insight gui.
 
  • Like
Reactions: 1 person
Status
Not open for further replies.