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
psshell 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