The debugger has the following predefined variables that you can set for debugging a program that forks:
When a fork occurs, the debugger sets the debugger variables $childprocess and $parentprocess to the child and parent process IDs, respectively.
In the following example, the debugger notifies you that the child process has stopped. The parent process continues to run.
(idb) set $catchforks = 1
(idb) run
Process 29027 forked. The child process is 29023.
Process 29023 stopped on fork.
stopped at [int main(void):6 0x120001178]
6 int pid = fork();
fork.c: I am the parent.
Process has exited with status 0
(idb) show process
>localhost:29028 (/home/user/examples/fork) loaded.
localhost:29023 (/home/user/examples/fork) paused.
In the preceding example, note the following:
Continuing the previous example, the following shows how to switch the debugger to the child process. Listing the source code shows the source for the child process.
(idb) process $childprocess
(idb) show process
localhost:29028 (/home/user/examples/fork) loaded.
>localhost:29023 (/home/user/examples/fork) paused.
(idb) list
7
8 if (pid == 0)
9 {
10 printf("fork.c: I am the child.\n");
11 }
12 else
13 {
14 printf("fork.c: I am the parent.\n");
15 }
16 }
In the preceding example, note the following:
If you catch the child but not the parent, and the parent code tries to execute a wait on the child, the target will get stuck if you don't let the child run to completion. This happens because the parent will be running but making no progress, and the child is stopped by the debugger. For example:
(idb) set $catchforks = 1
(idb) set $stopparentonfork = 0
(idb) list
10 int new_pid = 0;
11
12 if (pid == 0) {
13 printf( "fork.c: I am the child.\n" );
14 fflush( stdout );
15
16 } else {
17 printf( "fork.c: I am the parent, about to wait.\n" );
18 fflush( stdout );
19
20 new_pid = wait( &status );
21
22 printf( "fork.c: I am the parent, and my wait is finished\n" );
23
24 if (new_pid != pid )
25 printf( "\tthere was some error\n" );
26 else {
27 if (WIFEXITED(status))
28 printf( "\tthe child terminated normally\n" );
29
30 else if (WIFSIGNALED(status))
(idb) sh cat ./x.c_fork_hang.txt
If we 'cont' now, the process will fork; the child will be
caught and the parent will run to the 'wait' call and wait
for the child to terminate.
At that time, the child will be under debugger control,
but the current process will be the parent, which will be
running but making no progress. Only a Ctrl/C will allow
further progress.
The example program has set up another process to simulate
a Ctrl/C by the user. It will send SIGINT to the parent.
(idb) cont
Process 580893 forked. The child process is 580851.
Process 580851 stopped on fork.
stopped at [void test(void):9 0x120001318]
9 int pid = fork();
fork.c: I am the parent, about to wait.
:
User is waiting here
:
:
Sending SIGINT to parent process
:
Thread received signal INT
stopped at [<opaque> __wait4(...) 0x3ff800d0918]
Information: An <opaque> type was presented during execution of the previous command. For complete type information on this symbol, recompilation of the program will be necessary. Consult the compiler man pages for details on producing full symbol table information using the '-g' (and '-gall' for cxx) flags.
(idb) where
>0 0x3ff800d0918 in __wait4(...) in /usr/shlib/libc.so
#1 0x3ff800d668c in __wait(...) in /usr/shlib/libc.so
#2 0x120001398 in test() "c_fork_hang.c":20
#3 0x120001528 in main() "c_fork_hang.c":71
#4 0x1200012a8 in __start(...) in /home/user/examples/c_fork_hang
(idb) show process
>localhost:580893 (/home/user/examples/c_fork_hang) paused.
\_localhost:580851 (/home/user/examples/c_fork_hang) paused.