Multi-process GDB

This page describes the work to add multi-process support to GDB.

GDB HEAD already contains basic support for multi-process inferior control, and implements that in the remote target, but it can only be used to debug systems that share code across all inferiors. This project aims to extend that work by providing support for multi-process and multi-executable debugging for linux systems as well. This means being able to load several programs under a single GDB session; "run" or "attach" to several processes under a single GDB session, each possibly running a different program; or following all the forks and execs of an inferior and its children tree.

Getting the code / Helping

Discussions are held on the main GDB mailing list. Patches should be posted to the gdb-patches mailing list. Development is currently taking place on the mainline.

The original code for this effort was located in the multiprocess-20081120-branch branch in the CVS repository. It prototyped the specification posted here: specification. This is loselly based on Parallel Tools Consortium's High Performance Debugger Forum's Command Interface for Parallel Debugging (pdf file) (Old web site http://www.ptools.org/hpdf/).

During the 2009 the code in this branch become obsolete, the gdbserver work was merged into the trunk, just before the release only gdb multiexec work is still pending. The recent development is done in a set of patches, see http://sourceware.org/ml/gdb-patches/2009-07/msg00134.html.

Things found on the branch, not on mainline yet

To try out the multi-exec support, start GDB with several executables listed on the command line. You need to connect to gdbserver with 'target extended-remote' to run several processes simultaneously.

Running multiple processes simultaneously with gdbserver

Here's a small example, spawning several instances of the same executable.

Launch gdbserver in a separate terminal:

./gdbserver --multi :9999

Startup GDB, and load an example executable:

./gdb
(gdb) file /home/pedro/gdb/tests/threads
Reading symbols from /home/pedro/gdb/tests/threads...done.

Notice that executable files are listed as inferiors:

(gdb) info inferiors
  1 0 #threads# /home/pedro/gdb/tests/threads

Let's insert a breakpoint, and set it running. Notice that when debugging against a remote stub that supports "run", we have to separately tell it what to run.

(gdb) b main
Breakpoint 1 at 0x400640: file threads.c, line 35.
(gdb) set remote exec-file /home/pedro/gdb/tests/threads
(gdb) tar extended-remote :9999
Remote debugging using :9999
(gdb) run
Starting program: /home/pedro/gdb/tests/threads

Breakpoint 1, main () at threads.c:35
35          long i = 0;

You can issue more runs:

(gdb) r
Starting program: /home/pedro/gdb/tests/threads
[Switching to Thread 18132.18132]

Breakpoint 1, main () at threads.c:35
35          long i = 0;

The new inferior processes have been assigned internal inferior GDB ids, distinct from the executable inferior id:

(gdb) info inferiors
  3 18135 threads
* 2 18132 threads
  1 0 #threads# /home/pedro/gdb/tests/threads

The thread list holds all threads of all inferiors:

(gdb) info threads
  2 Thread 18135.18135  0x00007fd146ec2990 in _dl_debug_state () from /lib64/ld-linux-x86-64.so.2
* 1 Thread 18132.18132  main () at threads.c:35
(gdb)

Each inferior got a copy of the breakpoint location, so you can disable individual locations.

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>          inf 1
        breakpoint already hit 2 times
1.1                         y     0x0000000000400640 in main at threads.c:35 inf 1
1.2                         y     0x0000000000400640 in main at threads.c:35 inf 3
1.3                         y     0x0000000000400640 in main at threads.c:35 inf 2

branch TODO (some of this is out of date for mainline)

Here's the symptom, when starting a second instance of the same program:

(gdb) start
Temporary breakpoint 2 at 0x400640: file threads.c, line 35.
Starting program: /home/pedro/gdb/tests/threads
Warning:
Cannot insert breakpoint -2.
Error accessing memory address 0x7ffff7bc9790: Input/output error.
Cannot insert breakpoint -3.
Error accessing memory address 0x7ffff7bc97a0: Input/output error.

(gdb) maint info breakpoints
Num     Type           Disp Enb Address            What
-2      thread events  keep y   <MULTIPLE>          inf 0
-2.1                        y     0x00007ffff7bc9790  inf 0
-2.2                        y     0x00007ffff7bc9790  inf 2
-2.3                        y     0x00007ffff7bc9790  inf 3
-3      thread events  keep y   <MULTIPLE>          inf 0
-3.1                        y     0x00007ffff7bc97a0  inf 0
-3.2                        y     0x00007ffff7bc97a0  inf 2
-3.3                        y     0x00007ffff7bc97a0  inf 3
2       breakpoint     del  y   <MULTIPLE>          inf 1
2.1                         y     0x0000000000400640 in main at threads.c:35 inf 1
2.2                         y     0x0000000000400640 in main at threads.c:35 inf 3
2.3                         y     0x0000000000400640 in main at threads.c:35 inf 2
-4      shlib events   keep y   <MULTIPLE>          inf 0
-4.1                        y     0x00007ffff7dee990 <_dl_debug_state> inf 0
-4.2                        y     0x00007ffff7dee990 <_dl_debug_state> inf 3
-4.3                        y     0x00007ffff7dee990 <_dl_debug_state> inf 2
(gdb)                                                                              

The simplest solution would be to make thread event breakpoints inferior specific, so they aren't cloned across inferiors using the same exec.

(gdb) b main; run; run;...

(gdb) info inferiors
* 3 2311 foll-exec
  2 2308 foll-exec
  1 0 #foll-exec# /home/pedro/gdb/fsf_multi2/build/gdb/testsuite/gdb.base/foll-exec

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>          inf 1
        breakpoint already hit 2 times
1.1                         y     0x00000000004005c0 in main
                                               at ../../../src/gdb/testsuite/gdb.base/foll-exec.c:15 inf 1
1.2                         y     0x00000000004005c0 in main
                                               at ../../../src/gdb/testsuite/gdb.base/foll-exec.c:15 inf 3
1.3                         y     0x00000000004005c0 in main
                                               at ../../../src/gdb/testsuite/gdb.base/foll-exec.c:15 inf 2

Now, if we let inferior 3 run, and it execl's, GDB should try to reset breakpoints in its the new executable image. Symbolic breakpoints like "main", should be re-evaluated in the context of the new exec. inferior 2 is also using breakpoint 1 (through location 1.3), which means that we can't reset the whole breakpoint. We would have to reset only breakpoint location 1.2. Fixing this probably also touches the mechanism where we blindly clone breakpoint locations to all inferiors sharing the same exec (clone_breakpoint_location). This brings us to another issue:

None: MultiProcess (last edited 2009-08-24 23:20:55 by NickolayShmyrev)

All content (C) 2008 Free Software Foundation. For terms of use, redistribution, and modification, please see the WikiLicense page.