Debugging with gdb
The GNU debugger (gdb) allows you to examine the internals of another program while the program executes or retrospectively to see what a program was doing at the moment that it crashed.
The gdb allows you to examine and control the execution of code and is useful for evaluating the causes of crashes or general incorrect behavior. gdb does not handle Java™ processes, so it is of limited use on a pure Java program. It is useful for debugging native libraries and the JVM itself.
Running gdb
You can run gdb in three ways:
- Starting a program
- Typically the command:
gdb <application>
is used to start a program under the control of gdb. However, because of the way that Java is launched, you must start gdb by setting an environment variable and then calling Java:
Then you receive a gdb prompt, and you supply the run command and the Java arguments:export IBM_JVM_DEBUG_PROG=gdb java
r <java_arguments>
- Attaching to a running program
- If a Java program is already
running, you can control it under gdb. The process
ID of the running program is required, and then gdb is
started with the Java application
as the first argument and the process ID as the second argument:
gdb <Java Executable> <PID>
When gdb is attached to a running program, this program is halted and its position in the code is displayed for the viewer. The program is then under the control of gdb and you can start to issue commands to set and view the variables and generally control the execution of the code.
- Running on a system dump (corefile)
- A system dump is typically produced when a program crashes. gdb can
be run on this system dump. The system dump contains the state of
the program when the crash occurred. Use gdb to
examine the values of all the variables and registers leading up to
a crash. This information helps you discover what caused the crash.
To debug a system dump, start gdb with the Java application file as the first
argument and the system dump name as the second argument:
gdb <Java Executable> <system dump>
When you run gdb against a system dump, it initially shows information such as the termination signal the program received, the function that was executing at the time, and even the line of code that generated the fault.
When a program comes under the control of gdb, a welcome message is displayed followed by a prompt (gdb). The program is now waiting for you to enter instructions. For each instruction, the program continues in whichever way you choose.
Setting breakpoints and watchpoints
Breakpoints can be set for a particular line or function using the command:
break linenumber
or
break functionName
After you have set a breakpoint, use the continue command to allow the program to execute until it reaches a breakpoint.
Set breakpoints using conditionals so that the program halts only when the specified condition is reached. For example, using breakpoint 39 if var == value causes the program to halt when it reaches line 39, but only if the variable is equal to the specified value.
If you want to know where as well as when a variable became a certain value you can use a watchpoint. Set the watchpoint when the variable in question is in scope. After doing so, you will be alerted whenever this variable attains the specified value. The syntax of the command is: watch var == value.
To see which breakpoints and watchpoints are set, use the info command:
info break
info watch
handle sig32 pass nostop noprint
handle sigusr2 pass nostop noprint
Examining the code
backtrace
(abbreviated
to bt
), which shows the call stack. The call stack
is the collection of function frames, where each function frame contains
information such as function parameters and local variables. These
function frames are placed on the call stack in the order that they
are executed. This means that the most recently called function is
displayed at the top of the call stack. You can follow the trail of
execution of a program by examining the call stack. When the call
stack is displayed, it shows a frame number at the start of the line,
followed by the address of the calling function, followed by the function
name and the source file for the function. For example: #6 0x804c4d8 in myFunction () at myApplication.c
To view more detailed information about a function frame,
use the frame
command along with a parameter specifying
the frame number. After you have selected a frame, you can display
its variables using the command print var
.
Use
the print
command to change the value of a variable;
for example, print var = newValue
.
The info
locals
command displays the values of all local variables
in the selected function.
To follow the exact sequence of execution
of your program, use the step
and next
commands.
Both commands take an optional parameter specifying the number of
lines to execute. However, next
treats function calls
as a single line of execution, while step
progresses
through each line of the called function, one step at a time.
Useful commands
When you have finished debugging
your code, the run
command causes the program to
run through to its end or its crash point. The quit
command
is used to exit gdb.
Other useful commands are:
ptype
- Prints data type of variable.
info share
- Prints the names of the shared libraries that are currently loaded.
info functions
- Prints all the function prototypes.
list
- Shows the 10 lines of source code around the current line.
help
- Displays a list of subjects, each of which can have the help command called on it, to display detailed help on that topic.