3.4. Advanced GDB Features
This section presents advanced GDB features, some of which may make sense only after reading the Operating Systems chapter.
3.4.1. GDB and make
GDB accepts the make
command to rebuild an executable during a debugging
session, and if the build is successful it will run the newly built program
(when issued the run
command).
(gdb) make (gdb) run
Building from within GDB is convenient for a user who has set many breakpoints
and has fixed one bug but wants to continue the debugging session. In this
case, rather than quitting GDB, recompiling, restarting GDB with the new
executable, and resetting all the breakpoints, a GDB user can run make
and
start debugging the new version of the program with all the breakpoints still
set. Keep in mind, however, that modifying the C source and recompiling by
running make
from within GDB may result in the breakpoints not being at the
same logical location in the new version of the program as in the old version
if source code lines have been added or deleted. When this problem occurs,
either exit GDB and restart the GDB session on the new executable, or use
disable
or delete
to disable or delete the old breakpoints and then break
to
set new breakpoints at the correct locations in the newly compiled version of
the program.
3.4.2. Attaching GDB to a Running Process
GDB supports debugging a program that is already running (rather than starting a program to run from within a GDB session) by attaching GDB to a running process. To do this, the user needs to get the process ID (PID) value:
-
Get the process’s PID using the
ps
shell command:# ps to get process's PID (lists all processes started in current shell): $ ps # list all processes and pipe through grep for just those named a.out: $ ps -A | grep a.out PID TTY TIME CMD 12345 pts/3 00:00:00 a.out
-
Start GDB and attach it to the specific running process (with PID 12345):
# gdb <executable> <pid> $ gdb a.out 12345 (gdb) # OR alternative syntax: gdb attach <pid> <executable> $ gdb attach 12345 a.out (gdb)
Attaching GDB to a process pauses it, and the user can issue GDB commands before continuing its execution.
Alternatively, a program can explicitly pause itself to wait for debugging by
calling kill(getpid(), SIGSTOP)
(as in the
attach_example.c example). When the
program pauses at this point, a programmer can attach GDB to the process to
debug it.
Regardless of how a program pauses, after GDB attaches and the user enters some
GDB commands, the program’s execution continues from its attach point using
cont
. If cont
doesn’t work, GDB may need to explicitly send the process a
SIGCONT
signal in order to continue its execution:
(gdb) signal SIGCONT
3.4.3. Following a Process on a Fork
When GDB debugs a program that calls the fork()
function to create a
new child process, GDB can be set to follow (to debug) either the parent
process or the child process, leaving the execution of the other
process unaffected by GDB. By default, GDB follows the parent after
a call to fork()
. To set GDB to follow the child process, instead,
use the set follow-fork-mode
command:
(gdb) set follow-fork-mode child # Set gdb to follow child on fork (gdb) set follow-fork-mode parent # Set gdb to follow parent on fork (gdb) show follow-fork-mode # Display gdb's follow mode
Setting breakpoints at fork()
calls in the program is
useful when the user wants to change this behavior during a GDB
session.
The attach_example.c example shows one
way to "follow" both processes on a fork: GDB follows the parent process after
the fork, and the child sends itself a SIGSTOP
signal to explicitly pause
after the fork, allowing the programmer to attach a second GDB process to the
child before it continues.
3.4.4. Signal Control
The GDB process can send signals to the target process it is debugging and can handle signals received by the target process.
GDB can send signals to the process it debugs using the signal
command:
(gdb) signal SIGCONT (gdb) signal SIGALARM ...
Sometimes a user would like GDB to perform some action when a signal is received
by the debugged process. For example, if a program tries to access memory with
a misaligned memory address for the type it is accessing, it receives a
SIGBUS
signal and usually exits. The default behavior of GDB on a SIGBUS
is
also to let the process exit. If, however, you want GDB to examine the program
state when it receives a SIGBUS
, you can specify that GDB handle the SIGBUS
signal differently using the handle
command (the info
command shows
additional information about how GDB handles signals received by the process
during debugging):
(gdb) handle SIGBUS stop # if program gets a SIGBUS, gdb gets control (gdb) info signal # list info on all signals (gdb) info SIGALRM # list info just for the SIGALRM signal
3.4.5. DDD Settings and Bug Fixes
Running DDD creates a .ddd
directory in your home directory, which it uses to
store its settings so that users don’t need to reset all their preferences
from scratch on each invocation. Some examples of saved settings include sizes
of subwindows, menu display options, and enabling windows to view register
values and assembly code.
Sometimes DDD hangs on startup with a "Waiting until GDB ready" message.
This often indicates an error in its saved settings files. The easiest
way to fix this is remove the .ddd
directory (you will lose all your saved
settings and need to reset them when it starts up again):
$ rm -rf ~/.ddd # Be careful when entering this command! $ ddd ./a.out