GDB Debugging
GDB Debugging
introduction
Ferry Boender
Revision History
Revision 0.4 April 2004 Revised by: FB
1. About
This document contains a quick introduction on debugging using the GDB (GNU Debugger)
commandline client. GDB, although not a graphical debugging client, is a very powerfull debugger. Like
most Unix tools it has a pretty steep learning curve. This short tutorial like article will hopefully put you
on the right track in order to debug your programs using GDB.
This article focusses on debugging within a Unix enviroment, using program examples in the C language.
However, GDB is also supplied with the DJGPP package, which is a port of the GNU compiler-set for
DOS and Windows. Using GDB under Dos is not much different from using it under Unix.
2. Preperation
Before you will be able to debug your programs using GDB, you must first make sure that GDB knows
how your program works. It must know the names and places of functions, variables and various other
things. The info required is usually called the Debugging symbols. These debugging symbols are
contained within your executable, and GDB can read them so it can provide you with an altogether better
debugging experience.
Getting debugging symbols in your program is quite easy. If you are using a GNU compiler, for instance
GCC, G77 or G++, you can simply supply the -g parameter during the compile run. This will tell the
compiler to include debugging symbols in your program. I’m not sure if GDB will work with debugging
symbols generated by other compilers. If you’ve got more than one source file which you compile into
libs and then link them together, you should supply the -g parameter to each compile commandline.
An example. Suppose you have the following commandline to compile your program:
1
GDB Debugging: A quick introduction
$ gdb ./myprogram
This will place you at the GDB commandline and you are now ready to start debugging your program.
The screen will look something like this:
GDB also contains a semi-ncurses interface. This interface will show you the current source code
line/file which you are debugging. When the scope changes to another file, the display will automatically
change too. Most people prefer some kind of visual feedback, and if you are one of them you can use the
ncurses interface. Be advised though that it is quite buggy and will garble your display on more than one
occasion. (Yay GNU). To start gdb with the ncurses interface you must specify the --tui commandline
parameter when starting GDB.
--args
The --args parameter allows you to directly specify parameters which will not be used by GDB
himself but which will be passed along to the program you are debugging. The syntax for using it is:
gdb --args myprogram param1 param2
--commands=FILE
If you want to run automated tests than --commands+ is for you. You can simply supply a text-file
which contains the commands you wish to run automatically once GDB has been started. You might
first want to get to learn GDB though. Also check out the --batch parameter in the GDB help
documentation.
2
GDB Debugging: A quick introduction
4. Basic debugging
As you might have seen in earlier examples, GDB is a command line interface. This means you will be
provided with a prompt at which you can type commands. You might think this is arcane, and I won’t tell
you you’re wrong. If you’re not comfortable with a command-line you should perhaps check out another
debugging tool. But make no mistake: GDB is a very powerful tool. It is also available on most
development machines and Operating Systems. So perhaps it is a good idea if you at least know how to
perform basic debugging with it.
(gdb)
Type your commands at this line. During debugging, GDB will provide you with basic knowledge about
where you are debugging at the moment and the things that happen. When, for instance, I start the
program, and it hits a breakpoint, GDB will display:
The first line shows what happened. A breakpoint was triggered in the executable at the position which
corresponds to line 3 in the source of myprogram.c. The second line shows your current location in the
source file. GDB has now stopped due to the breakpoint and is awaiting your every command.
Sometimes, GDB’s output may seem somewhat cryptic. This is probably because sometimes it simply is.
You’ll get used to it.
A helpful tip might be that when you typed in a command once, you can then simply press the
return/enter key to execute the last command you entered.
Some of the basic commands with which you control the GDB program are:
run [args]
This starts the program which you want to debug. You may specify some parameters which will be
transfered to current program being debugged. (also see the set args command).
quit
3
GDB Debugging: A quick introduction
cd [path]
Set the current directory in which GDB and the file you are debugging operate in.
list [file]:[position]
The list command allows you to change the focus (note: NOT the scope of the current debugging
run) to another file. This allows you to set breakpoints and other things in another file which is part
of your total executable, for instance A library. It works by specifying the filename and / or the
position where you wish to list. The position can be either a linenumber, function name or an
address. Each time you issue list, the next 10 lines will be displayed. If you want to list the previous
10 lines instead, you may use the list - command. Some examples:
(gdb) list myexample.c:0
(gdb) list myexample.c:main
(gdb) list 10
(gdb) list myexampleslib.c:myfunction
We’ve already seen how we can start the program being debugged. If you wish to stop it, you can simply
switch to the debugging window (if you are debugging a graphical program) and press CTRL-C. This will
break off the execution of the current program and show you some information about where you
currently are.
If you wish to continue the program from the point where you pressed CTRL-C (or any other point where
the program was interrupted), simply type cont.
4.4. Backtracing
Whenever the program is interrupted, you can use the backtrace command to see what functions have
been called in order to bring you to the current location. This is especially neat when your program
segfaults. A small example:
#include <stdio.h>
4
GDB Debugging: A quick introduction
return (0);
}
This program will produce a segmentation fault because you are trying to copy a string into a memory
region (identified by ’s’) which has not been allocated. When the program is run, GDB will produce the
following output:
(gdb)backtrace
#0 0x4009bbc6 in strcpy () from /lib/tls/libc.so.6
#1 0x08048367 in main () at myprogram.c:6
This output is called a stack frame. The nice thing about this is that you can walk back through the
functions that have been called (strcpy() and main()) and view variables in the scope of that function.
Suppose the strcpy function was actually in a function named myfunc(), but the memory to which the
strcpy function copies the string was (not) initialised in main(). You can now use the up and down to
walk up and down the stack frame. When you enter a different stack frame you can view the contents of
it’s variables by using print.
You can also supply the full parameter to the backtrace command. This will make backtrace
automatically display all variable names and values in the scope of the stack frames.
4.5. Breakpoints
One of the most important aspects of a debugger are breakpoints. In GDB you can set breakpoints with
the appropriate break command. Breakpoints can be set on lines, functions or an address. Some
examples:
(gdb)break panel_list_jump
Breakpoint 1 at 0x8051d95: file panel.c, line 1093.
(gdb)break 100
Breakpoint 2 at 0x804da54: file nimf.c, line 100.
break [linenumber|function|address]
5
GDB Debugging: A quick introduction
info break
Delete the breakpoints identified by NR. If you specify no arguments all breakpoints will be deleted.
Tells GDB to ignore a breakpoint identified by NR for TIMES times. Suppose you have a for loop
which will run 20 times, but on the 10th time your program segfaults. You can issue the command
ignore 1 9 to ignore breakpoint 1 for 9 times.
commands [nr]
Any commands you enter here will be automatically run once a breakpoint hits. GDB will query
you for the commands you wish to run when you press enter. Example:
commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
> print *string
cont
end
Remember that the commands must work within the scope of the place where the breakpoint is set.
4.6. Stepping
Sometimes it can be beneficial to watch the program executing step by step. This can help you pinpoint
where exactly the program is producing errors or how it got to the part which is buggy. When stepping
through a program, GDB will execute one line in the current scope of the source-code each time. There
are two ways of stepping through a program:
step [TIMES]
This will execute the next line or, if TIMES is specified, the next TIMES lines. When the scope of the
program will change due to the step, GDB will follow the focus to the new scope and stop the
execution of the program there. This means that the step command always executes only one line of
code. For example, suppose you are debugging a program and the next line in the source-code is a
call to a function. When using step, GDB will step into the function and break off execution there.
6
GDB Debugging: A quick introduction
next [TIMES]
This will execute the next line or, if TIMES is specified, the next TIMES lines. When the scope of the
program will change due to the step, GDB will NOT follow the focus to the new scope. Instead,
GDB will treat the line as if it was a source-code line which didn’t change the focus. For instance,
when the next line is a function call, and you use next to execute the line, the function will be called
by GDB, but execution will continue until the program returns to where the function was called and
display the next line there for execution.
5. Data
Displaying data is a key aspect of debugging. The more you work with GDB, the more you will learn
about displaying data and the better you will become at easier tracking down problems. GDB provides a
number of ways in which you can view variable contents and other data.
5.1.1. print
You can use the print command to view the contents of variables and expressions. It’s usage is quite
simply:
print [expr]
The expression can be a variable name, a calculation and even a function call. Remember that you can
only access variables within the scope of the current stack frame. (See also the paragraph on
’Backtracing’) When printing a value, GDB will show the address of the variable and it’s value. GDB is
intelligent in that it automatically knows how to represent different variable types like string, integers,
structs, arrays and floating point values. It is possible to use typecasting to show variables in different
ways. For instance, to view the first character of a array of characters (otherwise known as a string), you
can issue the command: print (char)*string, or more easily: print s[0]. If you would like to
know the length of the string ’s’, you can issue a command like: print strlen(s).
You can specify formats in which the specified variables’ value should be shown. Formats are available
to more than just the print command. A format should be specified in the form of /[count][fmt] and
should go between the print (or any other command which supports formats, like x) command and the
variable you wish to print. count tells GDB to print the following count number of memory elements
too. You can’t use count with the print command, but you CAN use it with x. FMT can be any of these
formats:
• o, Octal
• x, Hexidecimal
7
GDB Debugging: A quick introduction
• d, Decimal
• u, Usigned decimal
• t, Binary
• f, Float
• a, Address
• i, Instruction (processor)
• c, Character
• s, String
Some examples
(gdb) print s
$1 = 0x804a008 "Kab", ’o’ <repeats 17 times>, "m!"
(gdb) print s[0]
$2 = 75 ’K’
(gdb) print /x s[0]
$3 = 0x4b
A more powerful command than print is the x command, which examines memory. It, too, supports
formats (see print command). With x, the COUNT parameter of formats is very important. It allows you
to view a block of memory in some kind of format. Here are some examples of ’x’ usage:
(gdb) x /20c s
0x804a008: 75 ’K’ 97 ’a’ 98 ’b’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’
0x804a010: 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’
0x804a018: 111 ’o’ 111 ’o’ 111 ’o’ 111 ’o’
(gdb) x /20x s
0x804a008: 0x4b 0x61 0x62 0x6f 0x6f 0x6f 0x6f 0x6f
0x804a010: 0x6f 0x6f 0x6f 0x6f 0x6f 0x6f 0x6f 0x6f
0x804a018: 0x6f 0x6f 0x6f 0x6f
In the above example we are displaying the memory region occupied by a string. The string has been
initiated in the corresponding C code by allocating 20 characters to the ’s’ string. As we can see when we
display the first 20 characters in this string that there isn’t a \0 character anywhere within the first 20
characters. This means that we have a buffer overrun, and thus a possible segmentation fault.
5.1.3. display
Use the display [EXPR] command to tell GDB to show a particular variables contents each time the
program is interrupted (breakpoints, CTRL-C, etc). display works in the same way as x does.
8
GDB Debugging: A quick introduction
Expressions, once again, can be anything from a simple variable-name, an memory address and even a
function. Use the undisplay command to stop displaying the data automatically. If you only want to
temporary stop displaying, you may use the disable display and enable display commands.
Both these commands require as a parameter the display rule. You can view all display rules by typing
display without any parameters.
6. Changing data
Changing data in a running program can be a very powerful tool. For example, one can use it to see what
happens when you assign some daft value to a variable in your program. Does it crash, or does it handle
it graceful? Or if you think you’ve finally found that nasty bug in your program and are preparing to
change the code accordingly. You could first alter some variables to see if the fix you thought would
bring an end to the suffering actually is the fix. Changing variables is also a great way to test all the
possibilities in a routine. (There’s a name for this, but I forgot what it was. Something along the lines of
touching every line of code?)
Changing data can be done with the set variable [EXPR] command. It’s a little confusing since set
is also used to change options in GDB itself. Adding to the confusion: you can, in most cases, abbreviate
the command and leave out the variable bit, so that the command becomes set [EXPR]
[EXPR] is an expression which assigns a value to a variable. For example, set my_linked_list =
NULL. The expression must be valid within the current scope. For some reason it does not seem possible
to use #define’d values in expressions. (If anybody can point out why this is, please let me know. It’s
quite annoying) The expression should adhere to the syntax of the language the program you are
debugging was written in. For C this would be set foo=5, for Pascal: set foo := 5.
You can also assign values to something called convenience variables. These variables are an extension
of GDB and they are not part of the program that you are debugging. A convenience variable is
prepended with a ’$’. For example, set $prev_i = i;.
7. Settings
GDB has an enormous ammount of settings. Some of the more usefull ones are:
9
GDB Debugging: A quick introduction
This setting changes the way GDB behaves when it encounters a fork() inside your program. Useful
for programs that spawn children. Possible options are: parent, child and ask. No explanation
needed I assume?
This lets GDB know how many lines it should display each time you run the list command.
GDB has the ability to log all output to a log-file. Nice if you want to review a debugging session.
Use set logging file [FILE] to specify to which file the log will be written. Next, set logging on will
turn on logging.
The print settings specify how data is printed by default. It has lots of different sub-options, of
which I personally only find the set print pretty on command useful. It makes print print structures
somewhat prettier.
There are many more settings which you can change. Please see the ’Getting help’ chapter for more
information
8. Getting help
GDB has lots of documentation, both in the GDB program itself as in various info and man pages.
Using the internal help system is easy. Type help at the command-line to get a overview of top-level
help topics. Issue help [SUBTOPIC] to view the commands in that subtopic. To get help on a specific
command, use help [COMMAND].
The info system on Unix systems holds the complete user manual for GDB, which is huge. Type info
gdb at the commandline to view it. You might need a separate 400 page manual on how to use ’info’
though. Some quick help: Press the enter key on anything which ends in ’::’ to follow that hyper-link.
Use the ’l’ key to return to the page which you were viewing before the current one.
9. Copyright / Author
Copyright (c) 2002-2004, Ferry Boender
10
GDB Debugging: A quick introduction
This document may be freely distributed, in part or as a whole, on any medium, without the prior
authorization of the author, provided that this Copyright notice remains intact, and there will be no
obstruction as to the further distribution of this document. You may not ask a fee for the contents of this
document, though a fee to compensate for the distribution of this document is permitted.
Modifications to this document are permitted, provided that the modified document is distributed under
the same license as the original document and no copyright notices are removed from this document. All
contents written by an author stays copyrighted by that author.
Failure to comply to one or all of the terms of this license automatically revokes your rights granted by
this license
All brand and product names mentioned in this document are trademarks or registered trademarks of
their respective holders.
Author:
Ferry Boender
<ferry (DOT) boender (AT) electricmonk (DOT) nl>
11