[RFC] [1/2] First cut at multi-executable support.

Pedro Alves
2009-06-15T15:22:40Z

Hi!

Here's a first cut at adding multi-executable support to GDB.

The biggest headache I had with this, is in being able to
model targets that share address spaces between inferiors,
while still allowing each inferior to have a "logical" address
space (e.g., uClinux); and at the same time, being able to
model targets where all inferiors that share a "logical" address
space, while each inferior has its own address space (e.g., DICOS);
all in all, while still allowing for the traditional model
of an inferior ~= address space ~= set of loaded symbols, but,
keeping in mind that either the main executable or shared libraries
can end up loaded at different offsets in different inferiors, even
if all inferiors were started from the same program (e.g.,
SOLIB_relocate_main_executable, PIE or address space randomization).

To that end, after much juggling around, and experimentation with
alternative designs, I've settled in this (I've pasted this before
in another thread):

/* A symbol space represents a symbolic view of an address space.
Roughly speaking, it holds all the data associated with a
non-running-yet program (main executable, main symbols), and when
an inferior is running and is bound to it, includes the list of its
mapped in shared libraries.

In the traditional debugging scenario, there's a 1-1 correspondence
among symbol spaces, inferiors and address spaces, like so:

sspace1 (prog1) <--> inf1(pid1) <--> aspace1

In the case of debugging more than one traditional unix process or
program, we still have:

|-----------------+------------+---------|
| sspace1 (prog1) | inf1(pid1) | aspace1 |
|----------------------------------------|
| sspace2 (prog1) | no inf yet | aspace2 |
|-----------------+------------+---------|
| sspace3 (prog2) | inf2(pid2) | aspace3 |
|-----------------+------------+---------|

In the former example, if inf1 forks (and GDB stays attached to
both processes), the new child will have its own symbol and address
spaces. Like so:

|-----------------+------------+---------|
| sspace1 (prog1) | inf1(pid1) | aspace1 |
|-----------------+------------+---------|
| sspace2 (prog1) | inf2(pid2) | aspace2 |
|-----------------+------------+---------|

However, had inf1 from the latter case vforked instead, it would
share the symbol and address spaces with its parent, until it execs
or exits, like so:

|-----------------+------------+---------|
| sspace1 (prog1) | inf1(pid1) | aspace1 |
| | inf2(pid2) | |
|-----------------+------------+---------|

When the vfork child execs, it is finally given new symbol and
address spaces.

|-----------------+------------+---------|
| sspace1 (prog1) | inf1(pid1) | aspace1 |
|-----------------+------------+---------|
| sspace2 (prog1) | inf2(pid2) | aspace2 |
|-----------------+------------+---------|

There are targets where the OS (if any) doesn't provide memory
management or VM protection, where all inferiors share the same
address space --- e.g. uClinux. GDB models by having all inferiors
share the same address space, but, giving each its own symbol
space, like so:

|-----------------+------------+---------|
| sspace1 (prog1) | inf1(pid1) | |
|-----------------+------------+ |
| sspace2 (prog1) | inf2(pid2) | aspace1 |
|-----------------+------------+ |
| sspace3 (prog2) | inf3(pid3) | |
|-----------------+------------+---------|

The address space sharing matters for run control and breakpoints
management. E.g., did we just hit a known breakpoint that we need
to step over? Is this breakpoint a duplicate of this other one, or
do I need to insert a trap?

Then, there are targets where all symbols look the same for all
inferiors, although each has its own address space, as e.g.,
Ericsson DICOS. In such case, the model is:

|---------+------------+---------|
| | inf1(pid1) | aspace1 |
| +------------+---------|
| sspace | inf2(pid2) | aspace2 |
| +------------+---------|
| | inf3(pid3) | aspace3 |
|---------+------------+---------|

Note however, that the DICOS debug API takes care of making GDB
believe that breakpoints are "global". That is, although each
process does have its own private copy of data symbols (just like a
bunch of forks), to the breakpoints module, all processes share a
single address space, so all breakpoints set at the same address
are duplicates of each other, even breakpoints set in the data
space (e.g., call dummy breakpoints placed on stack). This allows
a simplification in the spaces implementation: we avoid caring for
a many-many links between address and symbol spaces. Either
there's a single address space bound to the symbol space
(traditional unix/uClinux), or, in the DICOS case, the address
space bound to the symbol space is mostly ignored. */

There are still a few rough edges in that patch (you may find
it sometimes crashing), but, I've gone from small patch to huge
patch then to middle ground (this one), and went already in several
circles before settling on this, that I'd like to post it out there
for comments, and so that people can comment and experiment with it.
I'll also need to update all targets to make them bind an address/symbol
space to new inferiors. This patch only addresses core inferiors, linux
native and the remote target.

I haven't actually written docs for this yet, so, here are
a few examples of the patch in action:

Loading two different executables into GDB, and debugging them
simultaneously:

>./gdb -nx ./testsuite/gdb.base/break
GNU gdb (GDB) 6.8.50.20090611-cvs
(gdb) start
Temporary breakpoint 1 at 0x40061b: file ../../../src/gdb/testsuite/gdb.base/break.c, line 86.
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/break

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe398, envp=0x7fffffffe3a8)
at ../../../src/gdb/testsuite/gdb.base/break.c:86
86 if (argc == 12345) { /* an unlikely value < 2^16, in case uninited */ /* set breakpoint 6 here */
(gdb) add-symbol-space
Added symbol space 2 (sspace2)
1 symbol spaces added.
(gdb) sspace 2
[Switching to sspace 2]
(gdb) info sspaces
Id Main Program
* 2
1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/break
Bound inferiors: ID 1 (process 14959)
(gdb) file ./testsuite/gdb.base/advance
Reading symbols from /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance...done.
(gdb) info sspaces
Id Main Program
* 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance
1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/break
Bound inferiors: ID 1 (process 14959)
(gdb) start
Temporary breakpoint 2 at 0x4004ff: file ../../../src/gdb/testsuite/gdb.base/advance.c, line 41.
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance

Temporary breakpoint 2, main () at ../../../src/gdb/testsuite/gdb.base/advance.c:41
41 c = 5;
(gdb) info inferiors
Id Target ID SSpace Main Program
* 2 process 15009 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance
1 process 14959 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/break
(gdb) info sspaces
Id Main Program
* 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance
Bound inferiors: ID 2 (process 15009)
1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/break
Bound inferiors: ID 1 (process 14959)
(gdb)

==========================================================================

Debugging forks:

./gdb -nx ./testsuite/gdb.base/foll-fork
(gdb) start
Temporary breakpoint 1 at 0x4005df: file ../../../src/gdb/testsuite/gdb.base/foll-fork.c, line 22.
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-fork

Temporary breakpoint 1, main () at ../../../src/gdb/testsuite/gdb.base/foll-fork.c:22
22 int v = 5;
(gdb) set detach-on-fork off
(gdb) n
24 pid = fork ();
(gdb)
[New process 15107]
25 if (pid == 0) /* set breakpoint here */
(gdb) info inferiors
Id Target ID SSpace Main Program
2 process 15107 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-fork
* 1 process 15104 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-fork
(gdb) info sspaces
Id Main Program
2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-fork
Bound inferiors: ID 2 (process 15107)
* 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-fork
Bound inferiors: ID 1 (process 15104)

==========================================================================

Debugging vforks:

>./gdb -nx ./testsuite/gdb.base/foll-vfork
GNU gdb (GDB) 6.8.50.20090611-cvs
(gdb) set follow-fork-mode child
(gdb) set detach-on-fork off
(gdb) start
Temporary breakpoint 1 at 0x4005c0: file ../../../src/gdb/testsuite/gdb.base/foll-vfork.c, line 12.
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-vfork

Temporary breakpoint 1, main () at ../../../src/gdb/testsuite/gdb.base/foll-vfork.c:12
12 pid = vfork ();
(gdb) n
[New process 15175]
[Switching to process 15175]
13 if (pid == 0) {
(gdb) info inferiors
Id Target ID SSpace Main Program
* 2 process 15175 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-vfork
is vfork child of inferior 1
1 process 15170 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-vfork
is vfork parent of inferior 2
(gdb) info sspaces
Id Main Program
* 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/foll-vfork
Bound inferiors: ID 2 (process 15175), ID 1 (process 15170)

==========================================================================

Following execs in one of the (v)forks:

GNU make here vforked and execd shell, and the shell forked and
execd the crashme program, which, then crashes.

>cat Makefile.bug
all:
./crashme

>cat crashme.c
#include <stdlib.h>
#include <stdio.h>

int
main (int argc, char **argv)
{
int *foo = NULL;

printf ("Oh no, a bug!\n");

return *foo;
}

>./gdb -nx -quiet -ex "set target-async 1" -ex "set non-stop 1" --args /usr/bin/make -f Makefile.bug
(no debugging symbols found)
(gdb) info sspaces
Id Main Program
* 1 /usr/bin/make
(gdb) info sspaces
Id Main Program
* 1 /usr/bin/make
(gdb) set detach-on-fork off
(gdb) r&
Starting program: /usr/bin/make -f Makefile.bug
(no debugging symbols found)
(no debugging symbols found)
(gdb) (no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[Thread debugging using libthread_db enabled]
./crashme
[New process 15928]
[Thread debugging using libthread_db enabled]
process 15928 is executing new program: /home/pedro/gdb/sspaces/build/gdb/crashme
Oh no, a bug!

Program received signal SIGSEGV, Segmentation fault.
0x00000000004004bd in main (argc=1, argv=0x7fffffffe3d8) at crashme.c:11
11 return *foo;

==========================================================================

The same example, but let's place a breakpoint in the crashme
executable before invoking "make":

>./gdb -nx -quiet -ex "set target-async 1" -ex "set non-stop 1" --args /usr/bin/make -f Makefile.bug
(no debugging symbols found)
(gdb) add-symbol-space
Added symbol space 2 (sspace2)
1 symbol spaces added.
(gdb) sspace 2
[Switching to sspace 2]
(gdb) file ./crashme
Reading symbols from /home/pedro/gdb/sspaces/build/gdb/crashme...done.
(gdb) info sspaces
Id Main Program
* 2 /home/pedro/gdb/sspaces/build/gdb/crashme
1 /usr/bin/make
(gdb) b crashme.c:7
Breakpoint 1 at 0x4004a7: file crashme.c, line 7.
(gdb) sspace 1
[Switching to sspace 1 (/usr/bin/make)]
(gdb) show args
Argument list to give program being debugged when it is started is "-f Makefile.bug".
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004a7 in main at crashme.c:7 sspace 2
(gdb) set detach-on-fork off
(gdb) r&
Starting program: /usr/bin/make -f Makefile.bug
(no debugging symbols found)
(no debugging symbols found)
(gdb) (no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[Thread debugging using libthread_db enabled]
./crashme
[New process 16039]
[Thread debugging using libthread_db enabled]
process 16039 is executing new program: /home/pedro/gdb/sspaces/build/gdb/crashme

Breakpoint 1, main (argc=1, argv=0x7fffffffe3d8) at crashme.c:7
7 int *foo = NULL;
info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
breakpoint already hit 1 time
1.1 y 0x00000000004004a7 in main at crashme.c:7 sspace 3
1.2 y 0x00000000004004a7 in main at crashme.c:7 sspace 2
(gdb)

======================================================================================

Showing that symbolic breakpoints can resolve to different addresses in different
inferiors (actually more useful for attaching to existing processes than to
start up new ones).

>sysctl kernel.randomize_va_space
kernel.randomize_va_space = 1

>./gdb -quiet -nx -ex "set disable-randomization off" --args ./testsuite/gdb.base/shreloc
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(gdb) b fn_1
Breakpoint 1 at 0x400618
(gdb) r
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/shreloc

Breakpoint 1, fn_1 (referenced=0) at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9
9 ATTRIBUTES void fn_1 (int referenced) { static_var_1 = referenced; }
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00007f2dd1dcf533 in fn_1 at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9
breakpoint already hit 1 time
(gdb) clone-symbol-space
Added symbol space 2 (sspace2).
1 symbol spaces added.
(gdb) sspace 2
[Switching to sspace 2 (/home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/shreloc)]
(gdb) info sspaces
Id Main Program
* 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/shreloc
1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/shreloc
Bound inferiors: ID 1 (process 16171)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00007f2dd1dcf533 in fn_1
at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9 sspace 1
breakpoint already hit 1 time
(gdb) r
Starting program: /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/shreloc

Breakpoint 1, fn_1 (referenced=0) at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9
9 ATTRIBUTES void fn_1 (int referenced) { static_var_1 = referenced; }
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
breakpoint already hit 1 time
1.1 y 0x00007fe8b2221533 in fn_1
^^^^^^^^^^^^^^^^^^
at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9 sspace 2
1.2 y 0x00007f2dd1dcf533 in fn_1
^^^^^^^^^^^^^^^^^^
at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9 sspace 1
(gdb)

==================================================================================

Breakpoints by line number get expanded to all symbol spaces:

(gdb) del
Delete all breakpoints? (y or n) y
(gdb) b shreloc1.c:9
Breakpoint 2 at 0x7fe8b2221533: file ../../../src/gdb/testsuite/gdb.base/shreloc1.c, line 9. (2 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y <MULTIPLE>
2.1 y 0x00007fe8b2221533 in fn_1
at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9 sspace 2
2.2 y 0x00007f2dd1dcf533 in fn_1
at ../../../src/gdb/testsuite/gdb.base/shreloc1.c:9 sspace 1

==================================================================================

And the "bootstrapping" GDB example:

>cd build/gdb
>./gdb -ex "set detach off" -ex "set target-async 1" -ex "set non-stop 1" -ex "set schedule-multi" -ex "set follow-fork child" -ex "set pagination off" --args /usr/bin/make
(gdb) r&
...
:
[New process 16875]
[Thread debugging using libthread_db enabled]
process 16875 is executing new program: /bin/true
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program exited normally.
make[2]: Leaving directory `/home/pedro/gdb/sspaces/build/gdb/gdbserver'

Program exited normally.

Program exited normally.

Program exited normally.
make[1]: Leaving directory `/home/pedro/gdb/sspaces/build/gdb'

Program exited normally.

Program exited normally.

(gdb) info sspaces
Id Main Program
* 1 /usr/bin/make

==================================================================================

Oh, right, each inferior has its own set of shared libraries, and each can
load libthread_db independently of the others:

(gdb) info sspaces
Id Main Program
2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance
Bound inferiors: ID 2 (process 16982)
* 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.threads/manythreads
Bound inferiors: ID 3 (process 16995)
(gdb) info inferiors
Id Target ID SSpace Main Program
3 process 16995 1 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.threads/manythreads
* 2 process 16982 2 /home/pedro/gdb/sspaces/build/gdb/testsuite/gdb.base/advance
(gdb) inferior 2
[Switching to thread 2 (process 16982)]
#0 main () at ../../../src/gdb/testsuite/gdb.base/advance.c:41
41 c = 5;
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7de0a60 0x00007ffff7df6d44 Yes /lib64/ld-linux-x86-64.so.2
0x00007ffff7b62eb0 0x00007ffff7ba1258 Yes /lib/libm.so.6
0x00007ffff781ae30 0x00007ffff790be88 Yes /lib/libc.so.6
(gdb) inferior 3
[Switching to thread 3 (Thread 0x7ffff7fd66e0 (LWP 16995))]
#0 main (argc=1, argv=0x7fffffffe388) at ../../../src/gdb/testsuite/gdb.threads/manythreads.c:38
38 {
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7de0a60 0x00007ffff7df6d44 Yes /lib64/ld-linux-x86-64.so.2
0x00007ffff7bc9250 0x00007ffff7bd4038 Yes /lib/libpthread.so.0
0x00007ffff7946eb0 0x00007ffff7985258 Yes /lib/libm.so.6
0x00007ffff75fee30 0x00007ffff76efe88 Yes /lib/libc.so.6
(gdb)

==================================================================================

All-in-all, what do you think of this, and the patch below?

There's certainly scope of a lot of goodies to be added on top
of this, like extending thread control support (threads groups, itsets
or whatever); better support for symbol scoping a-la HPD's ## syntax
would be great too; Making the breakpoints module smarter about
that also would be nice. All big projects in themselves...

No changelog entry, tests or docs yet... But comments very welcome!

The new commands are:

info sspaces -- Info about currently known symbol spaces
sspace -- Change the current symbol space
add-symbol-space -- Add a new symbol space
clone-symbol-space -- Clone symbol space SPACE
remove-symbol-space -- Remove the symbol-space

This patch applies on top of:

http://sourceware.org/ml/gdb-patches/2009-05/msg00656.html

--
Pedro Alves

---
gdb/Makefile.in | 4
gdb/alpha-tdep.c | 3
gdb/arch-utils.c | 8
gdb/arch-utils.h | 2
gdb/arm-linux-tdep.c | 2
gdb/arm-tdep.c | 3
gdb/breakpoint.c | 541 +++++++++++++++++++------
gdb/breakpoint.h | 46 +-
gdb/corelow.c | 6
gdb/cris-tdep.c | 7
gdb/exec.c | 84 ++-
gdb/exec.h | 5
gdb/fork-child.c | 6
gdb/frame.c | 41 +
gdb/frame.h | 6
gdb/gdbarch.c | 24 +
gdb/gdbarch.h | 6
gdb/gdbarch.sh | 3
gdb/gdbcore.h | 9
gdb/gdbthread.h | 2
gdb/inf-ptrace.c | 2
gdb/infcall.c | 1
gdb/infcmd.c | 41 +
gdb/inferior.c | 70 ++-
gdb/inferior.h | 33 +
gdb/infrun.c | 361 +++++++++++++++-
gdb/linespec.c | 4
gdb/linux-fork.c | 12
gdb/linux-nat.c | 331 +++++++++++----
gdb/linux-tdep.c | 18
gdb/linux-thread-db.c | 18
gdb/mem-break.c | 2
gdb/mips-tdep.c | 12
gdb/objfiles.c | 4
gdb/objfiles.h | 69 ++-
gdb/printcmd.c | 26 +
gdb/record.c | 19
gdb/regcache.c | 20
gdb/regcache.h | 5
gdb/remote.c | 34 +
gdb/rs6000-aix-tdep.c | 3
gdb/rs6000-tdep.c | 3
gdb/solib-irix.c | 5
gdb/solib-svr4.c | 105 ++--
gdb/solib.c | 11
gdb/solib.h | 3
gdb/solist.h | 3
gdb/source.c | 30 +
gdb/sparc-tdep.c | 6
gdb/spu-tdep.c | 6
gdb/stack.c | 6
gdb/symfile.c | 2
gdb/symmisc.c | 48 +-
gdb/symspace.c | 709 +++++++++++++++++++++++++++++++++
gdb/symspace.h | 262 ++++++++++++
gdb/symtab.c | 66 ++-
gdb/symtab.h | 5
gdb/target.c | 25 +
gdb/target.h | 8
gdb/testsuite/config/monitor.exp | 2
gdb/testsuite/gdb.base/checkpoint.exp | 7
gdb/testsuite/gdb.base/foll-exec.exp | 10
gdb/testsuite/gdb.base/foll-fork.exp | 102 ++--
gdb/testsuite/gdb.base/foll-vfork.exp | 40 -
gdb/testsuite/gdb.base/maint.exp | 4
gdb/testsuite/gdb.base/multi-forks.exp | 4
gdb/thread.c | 22 +
gdb/top.c | 16
gdb/tui/tui-disasm.c | 4
69 files changed, 2830 insertions(+), 577 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/breakpoint.c 2009-06-15 15:24:22.000000000 +0100
@@ -113,7 +113,13 @@ static void breakpoint_adjustment_warnin
static CORE_ADDR adjust_breakpoint_address (CORE_ADDR bpaddr,
enum bptype bptype);

-static void describe_other_breakpoints (CORE_ADDR, struct obj_section *, int);
+static int breakpoint_address_match (struct address_space *aspace1,
+ CORE_ADDR addr1,
+ struct address_space *aspace2,
+ CORE_ADDR addr2);
+
+static void describe_other_breakpoints (struct symbol_space *,
+ CORE_ADDR, struct obj_section *, int);

static void breakpoints_info (char *, int);

@@ -141,6 +147,7 @@ typedef enum
insertion_state_t;

static int remove_breakpoint (struct bp_location *, insertion_state_t);
+static int remove_breakpoint_1 (struct bp_location *, insertion_state_t);

static enum print_stop_action print_it_typical (bpstat);

@@ -183,7 +190,8 @@ static void tcatch_command (char *arg, i

static void ep_skip_leading_whitespace (char **s);

-static int single_step_breakpoint_inserted_here_p (CORE_ADDR pc);
+static int single_step_breakpoint_inserted_here_p (struct address_space *,
+ CORE_ADDR pc);

static void free_bp_location (struct bp_location *loc);

@@ -393,6 +401,8 @@ int default_breakpoint_valid;
CORE_ADDR default_breakpoint_address;
struct symtab *default_breakpoint_symtab;
int default_breakpoint_line;
+struct symbol_space *default_breakpoint_sspace;
+
\f
/* *PP is a string denoting a breakpoint. Get the number of the breakpoint.
Advance *PP after the string and any trailing whitespace.
@@ -719,6 +729,9 @@ breakpoint_restore_shadows (gdb_byte *bu
continue;
if (!b->inserted)
continue;
+ if (b->target_info.placed_address_space != current_symbol_space->aspace)
+ continue;
+
/* Addresses and length of the part of the breakpoint that
we need to copy. */
bp_addr = b->target_info.placed_address;
@@ -873,6 +886,7 @@ update_watchpoint (struct breakpoint *b,
struct frame_id saved_frame_id;
struct bp_location *loc;
bpstat bs;
+ struct symbol_space *frame_sspace;

/* We don't free locations. They are stored in bp_location_chain and
update_global_locations will eventually delete them and remove
@@ -901,6 +915,8 @@ update_watchpoint (struct breakpoint *b,
select_frame (fi);
}

+ frame_sspace = get_frame_symbol_space (get_selected_frame (NULL));
+
if (within_current_scope && reparse)
{
char *s;
@@ -1002,6 +1018,7 @@ update_watchpoint (struct breakpoint *b,
for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
;
*tmp = loc;
+ loc->sspace = frame_sspace;
loc->address = addr;
loc->length = len;
loc->watchpoint_type = type;
@@ -1194,7 +1211,7 @@ Note: automatically using hardware break
if (val)
{
/* Can't set the breakpoint. */
- if (solib_name_from_address (bpt->address))
+ if (solib_name_from_address (bpt->sspace, bpt->address))
{
/* See also: disable_breakpoints_in_shlibs. */
val = 0;
@@ -1271,6 +1288,48 @@ Note: automatically using hardware break
return 0;
}

+/* This function is called when symbol space SSPACE is about to be
+ deleted. It takes care of updating breakpoints to not reference
+ SSPACE anymore. */
+
+void
+breakpoint_symbol_space_exit (struct symbol_space *sspace)
+{
+ struct breakpoint *b, *b_temp;
+ struct bp_location *loc, *loc_temp;
+
+ /* Remove any breakpoint that was set through this symbol space. */
+ ALL_BREAKPOINTS_SAFE (b, b_temp)
+ {
+ if (b->sspace == sspace)
+ delete_breakpoint (b);
+ }
+
+ /* Breakpoints set through other symbol spaces could have locations
+ bound to SSPACE as well. Remove those. */
+ ALL_BP_LOCATIONS_SAFE (loc, loc_temp)
+ {
+ struct bp_location *tmp;
+
+ if (loc->sspace == sspace)
+ {
+ if (loc->owner->loc == loc)
+ loc->owner->loc = loc->next;
+ else
+ for (tmp = loc->owner->loc; tmp->next != NULL; tmp = tmp->next)
+ if (tmp->next == loc)
+ {
+ tmp->next = loc->next;
+ break;
+ }
+ }
+ }
+
+ /* Now update the global location list to permanently delete the
+ removed locations above. */
+ update_global_location_list (0);
+}
+
/* Make sure all breakpoints are inserted in inferior.
Throws exception on any error.
A breakpoint that is already inserted won't be inserted
@@ -1314,9 +1373,15 @@ insert_breakpoint_locations (void)
/* Explicitly mark the warning -- this will only be printed if
there was an error. */
fprintf_unfiltered (tmp_error_stream, "Warning:\n");
-
+
+ save_current_space_and_thread ();
+
ALL_BP_LOCATIONS_SAFE (b, temp)
{
+ struct inferior *inf;
+ struct thread_info *tp;
+ CORE_ADDR last_addr;
+
if (!should_be_inserted (b) || b->inserted)
continue;

@@ -1326,6 +1391,16 @@ insert_breakpoint_locations (void)
&& !valid_thread_id (b->owner->thread))
continue;

+ switch_to_symbol_space_and_thread (b->sspace);
+
+ /* For targets that support global breakpoints, there's no need
+ to select an inferior to insert breakpoint to. In fact, even
+ if we aren't attached to any process yet, we should still
+ insert breakpoints. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch)
+ && ptid_equal (inferior_ptid, null_ptid))
+ continue;
+
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks,
&hw_breakpoint_error);
@@ -1405,6 +1480,28 @@ remove_breakpoints (void)
}

int
+remove_breakpoints_pid (int pid)
+{
+ struct bp_location *b;
+ int val;
+ struct inferior *inf = find_inferior_pid (pid);
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->sspace != inf->sspace)
+ continue;
+
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b, mark_uninserted);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
+int
remove_hw_watchpoints (void)
{
struct bp_location *b;
@@ -1425,17 +1522,30 @@ remove_hw_watchpoints (void)
int
reattach_breakpoints (int pid)
{
+ struct cleanup *old_chain;
struct bp_location *b;
int val;
- struct cleanup *old_chain = save_inferior_ptid ();
struct ui_file *tmp_error_stream = mem_fileopen ();
int dummy1 = 0, dummy2 = 0;
+ struct inferior *inf;
+ struct thread_info *tp;
+
+ tp = any_live_thread_of_process (pid);
+ if (tp == NULL)
+ return 1;
+
+ inf = find_inferior_pid (pid);
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = tp->ptid;

make_cleanup_ui_file_delete (tmp_error_stream);

- inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
+ if (b->sspace != inf->sspace)
+ continue;
+
if (b->inserted)
{
b->inserted = 0;
@@ -1464,6 +1574,7 @@ create_internal_breakpoint (CORE_ADDR ad

sal.pc = address;
sal.section = find_pc_overlay (sal.pc);
+ sal.sspace = current_symbol_space;

b = set_raw_breakpoint (sal, type);
b->number = internal_breakpoint_number--;
@@ -1516,10 +1627,14 @@ update_breakpoints_after_exec (void)
here instead, because there may be other attempts to delete
breakpoints after detecting an exec and before reaching here. */
ALL_BP_LOCATIONS (bploc)
- gdb_assert (!bploc->inserted);
+ if (bploc->sspace == current_symbol_space)
+ gdb_assert (!bploc->inserted);

ALL_BREAKPOINTS_SAFE (b, temp)
{
+ if (b->sspace != current_symbol_space)
+ continue;
+
/* Solib breakpoints must be explicitly reset after an exec(). */
if (b->type == bp_shlib_event)
{
@@ -1610,17 +1725,22 @@ detach_breakpoints (int pid)
struct bp_location *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
+ struct inferior *inf = current_inferior ();

if (pid == PIDGET (inferior_ptid))
error (_("Cannot detach breakpoints of inferior_ptid"));

- /* Set inferior_ptid; remove_breakpoint uses this global. */
+ /* Set inferior_ptid; remove_breakpoint_1 uses this global. */
inferior_ptid = pid_to_ptid (pid);
+
ALL_BP_LOCATIONS (b)
{
+ if (b->sspace != inf->sspace)
+ continue;
+
if (b->inserted)
{
- val = remove_breakpoint (b, mark_inserted);
+ val = remove_breakpoint_1 (b, mark_inserted);
if (val != 0)
{
do_cleanups (old_chain);
@@ -1632,10 +1752,17 @@ detach_breakpoints (int pid)
return 0;
}

+/* Remove the breakpoint location B from the current address space.
+ Note that this is used to detach breakpoints from a child fork.
+ When we get here, the child isn't in the inferior list, and neither
+ do we have objects to represent its address space --- we should
+ *not* look at b->sspace->aspace here. */
+
static int
-remove_breakpoint (struct bp_location *b, insertion_state_t is)
+remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
{
int val;
+ struct cleanup *old_chain;

if (b->owner->enable_state == bp_permanent)
/* Permanent breakpoints cannot be inserted or removed. */
@@ -1709,7 +1836,7 @@ remove_breakpoint (struct bp_location *b
/* In some cases, we might not be able to remove a breakpoint
in a shared library that has already been removed, but we
have not yet processed the shlib unload event. */
- if (val && solib_name_from_address (b->address))
+ if (val && solib_name_from_address (b->sspace, b->address))
val = 0;

if (val)
@@ -1745,6 +1872,32 @@ remove_breakpoint (struct bp_location *b
return 0;
}

+static int
+remove_breakpoint (struct bp_location *b, insertion_state_t is)
+{
+ int ret;
+ struct cleanup *old_chain;
+
+ if (b->owner->enable_state == bp_permanent)
+ /* Permanent breakpoints cannot be inserted or removed. */
+ return 0;
+
+ /* The type of none suggests that owner is actually deleted.
+ This should not ever happen. */
+ gdb_assert (b->owner->type != bp_none);
+
+ old_chain = save_current_space_and_thread ();
+
+ /* FIXME: When we support more than one address-space in a
+ symbol-space, this should switch to address-space. */
+ switch_to_symbol_space_and_thread (b->sspace);
+
+ ret = remove_breakpoint_1 (b, is);
+
+ do_cleanups (old_chain);
+ return ret;
+}
+
/* Clear the "inserted" flag in all breakpoints. */

void
@@ -1753,7 +1906,8 @@ mark_breakpoints_out (void)
struct bp_location *bpt;

ALL_BP_LOCATIONS (bpt)
- bpt->inserted = 0;
+ if (bpt->sspace == current_symbol_space)
+ bpt->inserted = 0;
}

/* Clear the "inserted" flag in all breakpoints and delete any
@@ -1774,6 +1928,7 @@ breakpoint_init_inferior (enum inf_conte
struct breakpoint *b, *temp;
struct bp_location *bpt;
int ix;
+ struct symbol_space *sspace = current_symbol_space;

/* If breakpoint locations are shared across processes, then there's
nothing to do. */
@@ -1781,11 +1936,17 @@ breakpoint_init_inferior (enum inf_conte
return;

ALL_BP_LOCATIONS (bpt)
- if (bpt->owner->enable_state != bp_permanent)
+ {
+ if (bpt->sspace == sspace
+ && bpt->owner->enable_state != bp_permanent)
bpt->inserted = 0;
+ }

ALL_BREAKPOINTS_SAFE (b, temp)
{
+ if (b->loc && b->loc->sspace != sspace)
+ continue;
+
switch (b->type)
{
case bp_call_dummy:
@@ -1828,6 +1989,11 @@ breakpoint_init_inferior (enum inf_conte
VEC_free (bp_location_p, moribund_locations);
}

+/* These functions concerns about actual breakpoints inserted in the
+ target --- to e.g. check if we need to do decr_pc adjustment or if
+ we need to hop over the bkpt --- so we check for address space
+ match, not symbol space. */
+
/* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
exists at PC. It returns ordinary_breakpoint_here if it's an
ordinary breakpoint, or permanent_breakpoint_here if it's a
@@ -1839,7 +2005,7 @@ breakpoint_init_inferior (enum inf_conte
the target, to advance the PC past the breakpoint. */

enum breakpoint_here
-breakpoint_here_p (CORE_ADDR pc)
+breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;
int any_breakpoint_here = 0;
@@ -1852,7 +2018,8 @@ breakpoint_here_p (CORE_ADDR pc)

if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
- && bpt->address == pc) /* bp is enabled and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -1871,13 +2038,14 @@ breakpoint_here_p (CORE_ADDR pc)
/* Return true if there's a moribund breakpoint at PC. */

int
-moribund_breakpoint_here_p (CORE_ADDR pc)
+moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
{
struct bp_location *loc;
int ix;

for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
- if (loc->address == pc)
+ if (breakpoint_address_match (loc->sspace->aspace, loc->address,
+ aspace, pc))
return 1;

return 0;
@@ -1889,7 +2057,7 @@ moribund_breakpoint_here_p (CORE_ADDR pc
inserted and removed using direct target manipulation. */

int
-regular_breakpoint_inserted_here_p (CORE_ADDR pc)
+regular_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;

@@ -1900,7 +2068,8 @@ regular_breakpoint_inserted_here_p (CORE
continue;

if (bpt->inserted
- && bpt->address == pc) /* bp is inserted and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -1917,12 +2086,12 @@ regular_breakpoint_inserted_here_p (CORE
or a single step breakpoint inserted at PC. */

int
-breakpoint_inserted_here_p (CORE_ADDR pc)
+breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
- if (regular_breakpoint_inserted_here_p (pc))
+ if (regular_breakpoint_inserted_here_p (aspace, pc))
return 1;

- if (single_step_breakpoint_inserted_here_p (pc))
+ if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;

return 0;
@@ -1932,7 +2101,7 @@ breakpoint_inserted_here_p (CORE_ADDR pc
inserted at PC. */

int
-software_breakpoint_inserted_here_p (CORE_ADDR pc)
+software_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;
int any_breakpoint_here = 0;
@@ -1943,7 +2112,8 @@ software_breakpoint_inserted_here_p (COR
continue;

if (bpt->inserted
- && bpt->address == pc) /* bp is enabled and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -1955,7 +2125,7 @@ software_breakpoint_inserted_here_p (COR
}

/* Also check for software single-step breakpoints. */
- if (single_step_breakpoint_inserted_here_p (pc))
+ if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;

return 0;
@@ -1965,7 +2135,8 @@ software_breakpoint_inserted_here_p (COR
PC is valid for process/thread PTID. */

int
-breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
+breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
+ ptid_t ptid)
{
const struct bp_location *bpt;
/* The thread and task IDs associated to PTID, computed lazily. */
@@ -1982,7 +2153,8 @@ breakpoint_thread_match (CORE_ADDR pc, p
&& bpt->owner->enable_state != bp_permanent)
continue;

- if (bpt->address != pc)
+ if (!breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
continue;

if (bpt->owner->thread != -1)
@@ -2837,7 +3009,8 @@ which its expression is valid.\n");
breakpoint location BL. This function does not check if we
should stop, only if BL explains the stop. */
static int
-bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
+bpstat_check_location (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
struct breakpoint *b = bl->owner;

@@ -2848,7 +3021,8 @@ bpstat_check_location (const struct bp_l
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catchpoint) /* a non-watchpoint bp */
{
- if (bl->address != bp_addr) /* address doesn't match */
+ if (!breakpoint_address_match (bl->sspace->aspace, bl->address,
+ aspace, bp_addr))
return 0;
if (overlay_debugging /* unmapped overlay section */
&& section_is_overlay (bl->section)
@@ -3068,7 +3242,8 @@ bpstat_check_breakpoint_conditions (bpst
commands, FIXME??? fields. */

bpstat
-bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
+bpstat_stop_status (struct address_space *aspace,
+ CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b = NULL;
const struct bp_location *bl;
@@ -3096,7 +3271,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
if (b->type == bp_hardware_watchpoint && bl != b->loc)
continue;

- if (!bpstat_check_location (bl, bp_addr))
+ if (!bpstat_check_location (bl, aspace, bp_addr))
continue;

/* Come here if it's a watchpoint, or if the break address matches */
@@ -3150,7 +3325,8 @@ bpstat_stop_status (CORE_ADDR bp_addr, p

for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
- if (loc->address == bp_addr)
+ if (breakpoint_address_match (loc->sspace->aspace, loc->address,
+ aspace, bp_addr))
{
bs = bpstat_alloc (loc, bs);
/* For hits of moribund locations, we should just proceed. */
@@ -3453,6 +3629,11 @@ static void print_breakpoint_location (s
char *wrap_indent,
struct ui_stream *stb)
{
+ struct cleanup *old_chain = save_current_symbol_space ();
+
+ if (loc != NULL)
+ set_current_symbol_space (loc->sspace);
+
if (b->source_file)
{
struct symbol *sym
@@ -3488,6 +3669,8 @@ static void print_breakpoint_location (s
print_address_symbolic (loc->address, stb->stream, demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
+
+ do_cleanups (old_chain);
}

/* Print B to gdb_stdout. */
@@ -3495,7 +3678,7 @@ static void
print_one_breakpoint_location (struct breakpoint *b,
struct bp_location *loc,
int loc_number,
- CORE_ADDR *last_addr)
+ CORE_ADDR *last_addr, int allflag)
{
struct command_line *l;
struct symbol *sym;
@@ -3670,6 +3853,18 @@ print_one_breakpoint_location (struct br
break;
}

+ /* For backward compatibility, don't display sspaces unless there
+ are several. */
+ if (!header_of_multiple
+ && (number_of_symbol_spaces () > 1 || allflag))
+ {
+ if (loc)
+ {
+ ui_out_text (uiout, " sspace ");
+ ui_out_field_int (uiout, "sspace", loc->sspace->num);
+ }
+ }
+
if (!part_of_multiple)
{
if (b->thread != -1)
@@ -3802,9 +3997,9 @@ print_one_breakpoint_location (struct br

static void
print_one_breakpoint (struct breakpoint *b,
- CORE_ADDR *last_addr)
+ CORE_ADDR *last_addr, int allflag)
{
- print_one_breakpoint_location (b, NULL, 0, last_addr);
+ print_one_breakpoint_location (b, NULL, 0, last_addr, allflag);

/* If this breakpoint has custom print function,
it's already printed. Otherwise, print individual
@@ -3827,7 +4022,7 @@ print_one_breakpoint (struct breakpoint
struct bp_location *loc;
int n = 1;
for (loc = b->loc; loc; loc = loc->next, ++n)
- print_one_breakpoint_location (b, loc, n, last_addr);
+ print_one_breakpoint_location (b, loc, n, last_addr, allflag);
}
}
}
@@ -3848,7 +4043,7 @@ do_captured_breakpoint_query (struct ui_
{
if (args->bnum == b->number)
{
- print_one_breakpoint (b, &dummy_addr);
+ print_one_breakpoint (b, &dummy_addr, 0);
return GDB_RC_OK;
}
}
@@ -3956,7 +4151,7 @@ breakpoint_1 (int bnum, int allflag)
/* We only print out user settable breakpoints unless the
allflag is set. */
if (allflag || user_settable_breakpoint (b))
- print_one_breakpoint (b, &last_addr);
+ print_one_breakpoint (b, &last_addr, allflag);
}

do_cleanups (bkpttbl_chain);
@@ -4006,29 +4201,34 @@ maintenance_info_breakpoints (char *bnum

static int
breakpoint_has_pc (struct breakpoint *b,
+ struct symbol_space *sspace,
CORE_ADDR pc, struct obj_section *section)
{
struct bp_location *bl = b->loc;
for (; bl; bl = bl->next)
{
- if (bl->address == pc
+ if (bl->sspace == sspace
+ && bl->address == pc
&& (!overlay_debugging || bl->section == section))
return 1;
}
return 0;
}

-/* Print a message describing any breakpoints set at PC. */
+/* Print a message describing any breakpoints set at PC. This
+ concerns with logical breakpoints, so we match symbol spaces, not
+ address spaces. */

static void
-describe_other_breakpoints (CORE_ADDR pc, struct obj_section *section,
+describe_other_breakpoints (struct symbol_space *sspace,
+ CORE_ADDR pc, struct obj_section *section,
int thread)
{
int others = 0;
struct breakpoint *b;

ALL_BREAKPOINTS (b)
- others += breakpoint_has_pc (b, pc, section);
+ others += breakpoint_has_pc (b, sspace, pc, section);
if (others > 0)
{
if (others == 1)
@@ -4036,7 +4236,7 @@ describe_other_breakpoints (CORE_ADDR pc
else /* if (others == ???) */
printf_filtered (_("Note: breakpoints "));
ALL_BREAKPOINTS (b)
- if (breakpoint_has_pc (b, pc, section))
+ if (breakpoint_has_pc (b, sspace, pc, section))
{
others--;
printf_filtered ("%d", b->number);
@@ -4064,10 +4264,12 @@ describe_other_breakpoints (CORE_ADDR pc
for the `break' command with no arguments. */

void
-set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
+set_default_breakpoint (int valid, struct symbol_space *sspace,
+ CORE_ADDR addr, struct symtab *symtab,
int line)
{
default_breakpoint_valid = valid;
+ default_breakpoint_sspace = sspace;
default_breakpoint_address = addr;
default_breakpoint_symtab = symtab;
default_breakpoint_line = line;
@@ -4101,6 +4303,15 @@ breakpoint_address_is_meaningful (struct
&& type != bp_catchpoint);
}

+static int
+breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
+ struct address_space *aspace2, CORE_ADDR addr2)
+{
+ return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ || aspace1 == aspace2)
+ && addr1 == addr2);
+}
+
/* Rescan breakpoints at the same address and section as BPT,
marking the first one as "first" and any others as "duplicates".
This is so that the bpt instruction is only inserted once.
@@ -4108,7 +4319,9 @@ breakpoint_address_is_meaningful (struct
that one the official one, and the rest as duplicates. */

static void
-check_duplicates_for (CORE_ADDR address, struct obj_section *section)
+check_duplicates_for (struct address_space *aspace,
+ CORE_ADDR address,
+ struct obj_section *section)
{
struct bp_location *b;
int count = 0;
@@ -4119,9 +4332,10 @@ check_duplicates_for (CORE_ADDR address,
&& b->owner->enable_state != bp_call_disabled
&& b->enabled
&& !b->shlib_disabled
- && b->address == address /* address / overlay match */
&& (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address))
{
/* Have we found a permanent breakpoint? */
if (b->owner->enable_state == bp_permanent)
@@ -4153,10 +4367,11 @@ check_duplicates_for (CORE_ADDR address,
if (b->owner->enable_state != bp_permanent
&& b->owner->enable_state != bp_disabled
&& b->owner->enable_state != bp_call_disabled
- && b->enabled && !b->shlib_disabled
- && b->address == address /* address / overlay match */
- && (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && b->enabled && !b->shlib_disabled
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address)
+ && (!overlay_debugging || b->section == section))
{
if (b->inserted)
internal_error (__FILE__, __LINE__,
@@ -4178,7 +4393,7 @@ check_duplicates (struct breakpoint *bpt
return;

for (; bl; bl = bl->next)
- check_duplicates_for (bl->address, bl->section);
+ check_duplicates_for (bl->sspace->aspace, bl->address, bl->section);
}

static void
@@ -4378,6 +4593,13 @@ set_raw_breakpoint (struct symtab_and_li
struct breakpoint *b = set_raw_breakpoint_without_location (bptype);
CORE_ADDR adjusted_address;

+ if (bptype != bp_catchpoint
+ && bptype != bp_watchpoint
+ && bptype != bp_read_watchpoint
+ && bptype != bp_access_watchpoint
+ && bptype != bp_hardware_watchpoint)
+ gdb_assert (sal.sspace != NULL);
+
/* Adjust the breakpoint's address prior to allocating a location.
Once we call allocate_bp_location(), that mostly uninitialized
location will be placed on the location chain. Adjustment of the
@@ -4389,6 +4611,11 @@ set_raw_breakpoint (struct symtab_and_li
b->loc = allocate_bp_location (b);
b->loc->requested_address = sal.pc;
b->loc->address = adjusted_address;
+ b->loc->sspace = sal.sspace;
+
+ /* Store the symbol space that was used to set the breakpoint, for
+ breakpoint resetting. */
+ b->sspace = sal.sspace;

if (sal.symtab == NULL)
b->source_file = NULL;
@@ -4514,7 +4741,8 @@ remove_thread_event_breakpoints (void)
struct breakpoint *b, *temp;

ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_thread_event)
+ if (b->type == bp_thread_event
+ && b->loc->sspace == current_symbol_space)
delete_breakpoint (b);
}

@@ -4539,7 +4767,8 @@ remove_solib_event_breakpoints (void)
struct breakpoint *b, *temp;

ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_shlib_event)
+ if (b->type == bp_shlib_event
+ && b->loc->sspace == current_symbol_space)
delete_breakpoint (b);
}

@@ -4572,11 +4801,12 @@ disable_breakpoints_in_shlibs (void)
if (((b->type == bp_breakpoint)
|| (b->type == bp_hardware_breakpoint)
|| (b->type == bp_tracepoint))
+ && loc->sspace == current_symbol_space
&& !loc->shlib_disabled
#ifdef PC_SOLIB
&& PC_SOLIB (loc->address)
#else
- && solib_name_from_address (loc->address)
+ && solib_name_from_address (loc->sspace, loc->address)
#endif
)
{
@@ -4607,6 +4837,7 @@ disable_breakpoints_in_unloaded_shlib (s
struct breakpoint *b = loc->owner;
if ((loc->loc_type == bp_loc_hardware_breakpoint
|| loc->loc_type == bp_loc_software_breakpoint)
+ && solib->sspace == loc->sspace
&& !loc->shlib_disabled
&& (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)
&& solib_contains_address_p (solib, loc->address))
@@ -4810,6 +5041,7 @@ create_catchpoint (int tempflag, char *c
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
+ sal.sspace = current_symbol_space;

b = set_raw_breakpoint (sal, bp_catchpoint);
set_breakpoint_count (breakpoint_count + 1);
@@ -5026,6 +5258,7 @@ clone_momentary_breakpoint (struct break
copy->loc->requested_address = orig->loc->requested_address;
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
+ copy->loc->sspace = orig->loc->sspace;

if (orig->source_file == NULL)
copy->source_file = NULL;
@@ -5209,6 +5442,11 @@ add_location_to_breakpoint (struct break
*tmp = loc;
loc->requested_address = sal->pc;
loc->address = adjust_breakpoint_address (loc->requested_address, b->type);
+
+ loc->sspace = sal->sspace;
+
+ gdb_assert (loc->sspace != NULL);
+
loc->section = sal->section;

set_breakpoint_location_function (loc);
@@ -5243,7 +5481,10 @@ bp_loc_is_permanent (struct bp_location
/* Enable the automatic memory restoration from breakpoints while
we read the memory. Otherwise we could say about our temporary
breakpoints they are permanent. */
- cleanup = make_show_memory_breakpoints_cleanup (0);
+ cleanup = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (loc->sspace);
+ make_show_memory_breakpoints_cleanup (0);

if (target_read_memory (loc->address, target_mem, len) == 0
&& memcmp (target_mem, brk, len) == 0)
@@ -5288,7 +5529,7 @@ create_breakpoint (struct symtabs_and_li
struct bp_location *loc;

if (from_tty)
- describe_other_breakpoints (sal.pc, sal.section, thread);
+ describe_other_breakpoints (sal.sspace, sal.pc, sal.section, thread);

if (i == 0)
{
@@ -5329,6 +5570,8 @@ create_breakpoint (struct symtabs_and_li
me. */
b->addr_string = xstrprintf ("*0x%s", paddr (b->loc->address));

+ b->sspace = sals.sals[0].sspace;
+
b->ops = ops;
mention (b);
}
@@ -5347,20 +5590,19 @@ remove_sal (struct symtabs_and_lines *sa
--(sal->nelts);
}

-/* If appropriate, obtains all sals that correspond
- to the same file and line as SAL. This is done
- only if SAL does not have explicit PC and has
- line and file information. If we got just a single
- expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out
- all sals for which the name of enclosing function
- is different from SAL. This makes sure that if we have
- breakpoint originally set in template instantiation, say
- foo<int>(), we won't expand SAL to locations at the same
- line in all existing instantiations of 'foo'.
+/* If appropriate, obtains all sals that correspond to the same file
+ and line as SAL, in all symbol spaces. Users debugging with IDEs,
+ will want to set a breakpoint at foo.c:line, and not really care
+ about symbol spaces. This is done only if SAL does not have
+ explicit PC and has line and file information. If we got just a
+ single expanded sal, return the original.
+
+ Otherwise, if SAL.explicit_line is not set, filter out all sals for
+ which the name of enclosing function is different from SAL. This
+ makes sure that if we have breakpoint originally set in template
+ instantiation, say foo<int>(), we won't expand SAL to locations at
+ the same line in all existing instantiations of 'foo'. */

-*/
static struct symtabs_and_lines
expand_line_sal_maybe (struct symtab_and_line sal)
{
@@ -5369,6 +5611,7 @@ expand_line_sal_maybe (struct symtab_and
char *original_function = NULL;
int found;
int i;
+ struct cleanup *old_chain;

/* If we have explicit pc, don't expand.
If we have no line number, we can't expand. */
@@ -5381,9 +5624,16 @@ expand_line_sal_maybe (struct symtab_and
}

sal.pc = 0;
+
+ old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (sal.sspace);
+
find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
+
+ /* Note that expand_line_sal visits *all* symbol spaces. */
expanded = expand_line_sal (sal);
+
if (expanded.nelts == 1)
{
/* We had one sal, we got one sal. Without futher
@@ -5393,6 +5643,7 @@ expand_line_sal_maybe (struct symtab_and
expanded.sals = xmalloc (sizeof (struct symtab_and_line));
sal.pc = original_pc;
expanded.sals[0] = sal;
+ do_cleanups (old_chain);
return expanded;
}

@@ -5403,6 +5654,11 @@ expand_line_sal_maybe (struct symtab_and
{
CORE_ADDR pc = expanded.sals[i].pc;
char *this_function;
+
+ /* We need to switch threads as well since we're about to
+ read memory. */
+ switch_to_symbol_space_and_thread (expanded.sals[i].sspace);
+
if (find_pc_partial_function (pc, &this_function,
&func_addr, &func_end))
{
@@ -5427,7 +5683,8 @@ expand_line_sal_maybe (struct symtab_and
}
}

-
+ do_cleanups (old_chain);
+
if (expanded.nelts <= 1)
{
/* This is un ugly workaround. If we get zero
@@ -5518,6 +5775,7 @@ parse_breakpoint_sals (char **address,
sal.pc = default_breakpoint_address;
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
+ sal.sspace = default_breakpoint_sspace;
sal.section = find_pc_overlay (sal.pc);

/* "break" without arguments is equivalent to "break *PC" where PC is
@@ -5835,6 +6093,7 @@ break_command_really (char *arg, char *c
b->condition_not_parsed = 1;
b->ops = ops;
b->enable_state = enabled ? bp_enabled : bp_disabled;
+ b->sspace = current_symbol_space;

mention (b);
}
@@ -5900,15 +6159,24 @@ set_breakpoint (char *address, char *con
static void
skip_prologue_sal (struct symtab_and_line *sal)
{
- struct symbol *sym = find_pc_function (sal->pc);
+ struct symbol *sym;
struct symtab_and_line start_sal;
+ struct cleanup *old_chain = save_current_space_and_thread ();

- if (sym == NULL)
- return;
+ /* We need to switch threads as well since we're about to read
+ memory. */
+ switch_to_symbol_space_and_thread (sal->sspace);
+
+ sym = find_pc_function (sal->pc);

- start_sal = find_function_start_sal (sym, 1);
- if (sal->pc < start_sal.pc)
- *sal = start_sal;
+ if (sym != NULL)
+ {
+ start_sal = find_function_start_sal (sym, 1);
+ if (sal->pc < start_sal.pc)
+ *sal = start_sal;
+ }
+
+ do_cleanups (old_chain);
}

/* Helper function for break_command_1 and disassemble_command. */
@@ -5959,10 +6227,15 @@ resolve_sal_pc (struct symtab_and_line *
source). */

struct minimal_symbol *msym;
+ struct cleanup *old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (sal->sspace);

msym = lookup_minimal_symbol_by_pc (sal->pc);
if (msym)
sal->section = SYMBOL_OBJ_SECTION (msym);
+
+ do_cleanups (old_chain);
}
}
}
@@ -6153,6 +6426,8 @@ watch_command_1 (char *arg, int accessfl
}
}

+ sal.sspace = current_symbol_space;
+
/* Parse the rest of the arguments. */
innermost_block = NULL;
exp_start = arg;
@@ -6818,7 +7093,7 @@ create_ada_exception_breakpoint (struct

if (from_tty)
{
- describe_other_breakpoints (sal.pc, sal.section, -1);
+ describe_other_breakpoints (sal.sspace, sal.pc, sal.section, -1);
/* FIXME: brobecker/2006-12-28: Actually, re-implement a special
version for exception catchpoints, because two catchpoints
used for different exception names will use the same address.
@@ -6933,6 +7208,7 @@ clear_command (char *arg, int from_tty)
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
sal.pc = default_breakpoint_address;
+ sal.sspace = default_breakpoint_sspace;
if (sal.symtab == 0)
error (_("No source file specified."));

@@ -6996,13 +7272,15 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
+ int pc_match = sal.pc
+ && (loc->sspace == sal.sspace)
&& (loc->address == sal.pc)
&& (!section_is_overlay (loc->section)
|| loc->section == sal.section);
int line_match = ((default_match || (0 == sal.pc))
&& b->source_file != NULL
&& sal.symtab != NULL
+ && sal.sspace == loc->sspace
&& strcmp (b->source_file, sal.symtab->filename) == 0
&& b->line_number == sal.line);
if (pc_match || line_match)
@@ -7171,8 +7449,12 @@ update_global_location_list (int should_
call to check_duplicates will fix up this later. */
loc2->duplicate = 0;
if (should_be_inserted (loc2)
- && loc2 != loc && loc2->address == loc->address)
- {
+ && loc2 != loc
+ && breakpoint_address_match (loc2->sspace->aspace,
+ loc2->address,
+ loc->sspace->aspace,
+ loc->address))
+ {
loc2->inserted = 1;
loc2->target_info = loc->target_info;
keep_in_target = 1;
@@ -7552,7 +7834,8 @@ update_breakpoint_locations (struct brea
if (have_ambiguous_names)
{
for (; l; l = l->next)
- if (e->address == l->address)
+ if (breakpoint_address_match (e->sspace->aspace, e->address,
+ l->sspace->aspace, l->address))
{
l->enabled = 0;
break;
@@ -7589,12 +7872,12 @@ breakpoint_re_set_one (void *bint)
int i;
int not_found = 0;
int *not_found_ptr = &not_found;
- struct symtabs_and_lines sals = {};
- struct symtabs_and_lines expanded;
+ struct symtabs_and_lines sals = {0};
+ struct symtabs_and_lines expanded = {0};
char *s;
enum enable_state save_enable;
struct gdb_exception e;
- struct cleanup *cleanups;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);

switch (b->type)
{
@@ -7615,6 +7898,10 @@ breakpoint_re_set_one (void *bint)
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
+
+ save_current_space_and_thread ();
+ switch_to_symbol_space_and_thread (b->sspace);
+
TRY_CATCH (e, RETURN_MASK_ERROR)
{
sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
@@ -7648,29 +7935,31 @@ breakpoint_re_set_one (void *bint)
}
}

- if (not_found)
- break;
-
- gdb_assert (sals.nelts == 1);
- resolve_sal_pc (&sals.sals[0]);
- if (b->condition_not_parsed && s && s[0])
- {
- char *cond_string = 0;
- int thread = -1;
- int task = 0;
-
- find_condition_and_thread (s, sals.sals[0].pc,
- &cond_string, &thread, &task);
- if (cond_string)
- b->cond_string = cond_string;
- b->thread = thread;
- b->task = task;
- b->condition_not_parsed = 0;
+ if (!not_found)
+ {
+ gdb_assert (sals.nelts == 1);
+
+ resolve_sal_pc (&sals.sals[0]);
+ if (b->condition_not_parsed && s && s[0])
+ {
+ char *cond_string = 0;
+ int thread = -1;
+ int task = 0;
+
+ find_condition_and_thread (s, sals.sals[0].pc,
+ &cond_string, &thread, &task);
+ if (cond_string)
+ b->cond_string = cond_string;
+ b->thread = thread;
+ b->task = task;
+ b->condition_not_parsed = 0;
+ }
+
+ expanded = expand_line_sal_maybe (sals.sals[0]);
}
- expanded = expand_line_sal_maybe (sals.sals[0]);
- cleanups = make_cleanup (xfree, sals.sals);
+
+ make_cleanup (xfree, sals.sals);
update_breakpoint_locations (b, expanded);
- do_cleanups (cleanups);
break;

case bp_watchpoint:
@@ -7741,6 +8030,7 @@ breakpoint_re_set_one (void *bint)
break;
}

+ do_cleanups (cleanups);
return 0;
}

@@ -7755,9 +8045,12 @@ breakpoint_re_set_objfile (struct objfil
struct breakpoint *b, *temp;
enum language save_language;
int save_input_radix;
+ struct cleanup *old_chain;

save_language = current_language->la_language;
save_input_radix = input_radix;
+ old_chain = save_current_symbol_space ();
+
ALL_BREAKPOINTS_SAFE (b, temp)
{
/* Format possible error msg */
@@ -7770,9 +8063,16 @@ breakpoint_re_set_objfile (struct objfil
set_language (save_language);
input_radix = save_input_radix;

+ do_cleanups (old_chain);
+
if (objfile == NULL)
- ALL_OBJFILES (objfile)
- create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
+ {
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
+ }
else
create_overlay_event_breakpoint ("_ovly_debug_event", objfile);
}
@@ -7796,6 +8096,12 @@ breakpoint_re_set_thread (struct breakpo
{
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
+
+ /* We're being called after following a fork. The new fork is
+ selected as current, and unless this was a vfork will have a
+ different symbol space from the original thread. Reset that
+ as well. */
+ b->loc->sspace = current_symbol_space;
}
}

@@ -8166,14 +8472,15 @@ decode_line_spec_1 (char *string, int fu
someday. */

void *
-deprecated_insert_raw_breakpoint (CORE_ADDR pc)
+deprecated_insert_raw_breakpoint (struct address_space *aspace, CORE_ADDR pc)
{
struct bp_target_info *bp_tgt;

- bp_tgt = xmalloc (sizeof (struct bp_target_info));
- memset (bp_tgt, 0, sizeof (struct bp_target_info));
+ bp_tgt = XZALLOC (struct bp_target_info);

+ bp_tgt->placed_address_space = aspace;
bp_tgt->placed_address = pc;
+
if (target_insert_breakpoint (bp_tgt) != 0)
{
/* Could not insert the breakpoint. */
@@ -8205,7 +8512,7 @@ static void *single_step_breakpoints[2];
/* Create and insert a breakpoint for software single step. */

void
-insert_single_step_breakpoint (CORE_ADDR next_pc)
+insert_single_step_breakpoint (struct address_space *aspace, CORE_ADDR next_pc)
{
void **bpt_p;

@@ -8224,7 +8531,7 @@ insert_single_step_breakpoint (CORE_ADDR
corresponding changes elsewhere where single step breakpoints are
handled, however. So, for now, we use this. */

- *bpt_p = deprecated_insert_raw_breakpoint (next_pc);
+ *bpt_p = deprecated_insert_raw_breakpoint (aspace, next_pc);
if (*bpt_p == NULL)
error (_("Could not insert single-step breakpoint at 0x%s"),
paddr_nz (next_pc));
@@ -8252,14 +8559,16 @@ remove_single_step_breakpoints (void)
/* Check whether a software single-step breakpoint is inserted at PC. */

static int
-single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
+single_step_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
int i;

for (i = 0; i < 2; i++)
{
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
- if (bp_tgt && bp_tgt->placed_address == pc)
+ if (bp_tgt
+ && bp_tgt->placed_address_space == aspace
+ && bp_tgt->placed_address == pc)
return 1;
}

Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/breakpoint.h 2009-06-15 15:24:22.000000000 +0100
@@ -159,6 +159,9 @@ enum target_hw_bp_type

struct bp_target_info
{
+ /* Address space at which the breakpoint was placed. */
+ struct address_space *placed_address_space;
+
/* Address at which the breakpoint was placed. This is normally the
same as ADDRESS from the bp_location, except when adjustment
happens in gdbarch_breakpoint_from_pc. The most common form of
@@ -251,6 +254,16 @@ struct bp_location
/* Data for specific breakpoint types. These could be a union, but
simplicity is more important than memory usage for breakpoints. */

+ /* The symbol space associated with this breakpoint location
+ address. Note that an address space may be represented in more
+ than one symbol space (e.g. each uclinux program will be given
+ its own symbol space, but there will only be one address space
+ for all of them), but we must not insert more than one location
+ at the same address in the same address space. Note that the
+ condition expression associated with this location can involve
+ more than one symbol space. */
+ struct symbol_space *sspace;
+
/* Note that zero is a perfectly valid code address on some platforms
(for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
is not a special value for this field. Valid for all types except
@@ -385,6 +398,9 @@ struct breakpoint
equals this. */
struct frame_id frame_id;

+ /* The symbol space used to set the breakpoint. */
+ struct symbol_space *sspace;
+
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
/* Language we used to set the breakpoint. */
@@ -488,7 +504,8 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);

-extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
+extern bpstat bpstat_stop_status (struct address_space *aspace,
+ CORE_ADDR pc, ptid_t ptid);
\f
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@@ -672,17 +689,17 @@ enum breakpoint_here

/* Prototypes for breakpoint-related functions. */

-extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
+extern enum breakpoint_here breakpoint_here_p (struct address_space *, CORE_ADDR);

-extern int moribund_breakpoint_here_p (CORE_ADDR);
+extern int moribund_breakpoint_here_p (struct address_space *, CORE_ADDR);

-extern int breakpoint_inserted_here_p (CORE_ADDR);
+extern int breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);

-extern int regular_breakpoint_inserted_here_p (CORE_ADDR);
+extern int regular_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);

-extern int software_breakpoint_inserted_here_p (CORE_ADDR);
+extern int software_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);

-extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
+extern int breakpoint_thread_match (struct address_space *, CORE_ADDR, ptid_t);

extern void until_break_command (char *, int, int);

@@ -700,7 +717,8 @@ extern struct breakpoint *clone_momentar

extern void set_ignore_count (int, int, int);

-extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
+extern void set_default_breakpoint (int, struct symbol_space *,
+ CORE_ADDR, struct symtab *, int);

extern void breakpoint_init_inferior (enum inf_context);

@@ -730,6 +748,8 @@ extern void insert_breakpoints (void);

extern int remove_breakpoints (void);

+extern int remove_breakpoints_pid (int pid);
+
/* This function can be used to physically insert eventpoints from the
specified traced inferior process, without modifying the breakpoint
package's state. This can be useful for those targets which support
@@ -765,6 +785,11 @@ extern void update_breakpoints_after_exe
inferior_ptid. */
extern int detach_breakpoints (int);

+/* This function is called when symbol space SSPACE is about to be
+ deleted. It takes care of updating breakpoints to not reference
+ this SSPACE anymore. */
+extern void breakpoint_symbol_space_exit (struct symbol_space *sspace);
+
extern void set_longjmp_breakpoint (void);
extern void delete_longjmp_breakpoint (int thread);

@@ -850,13 +875,14 @@ extern int remove_hw_watchpoints (void);

/* Manage a software single step breakpoint (or two). Insert may be called
twice before remove is called. */
-extern void insert_single_step_breakpoint (CORE_ADDR);
+extern void insert_single_step_breakpoint (struct address_space *, CORE_ADDR);
extern void remove_single_step_breakpoints (void);

/* Manage manual breakpoints, separate from the normal chain of
breakpoints. These functions are used in murky target-specific
ways. Please do not add more uses! */
-extern void *deprecated_insert_raw_breakpoint (CORE_ADDR);
+extern void *deprecated_insert_raw_breakpoint (struct address_space *,
+ CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (void *);

/* Check if any hardware watchpoints have triggered, according to the
Index: src/gdb/corelow.c
===================================================================
--- src.orig/gdb/corelow.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/corelow.c 2009-06-15 15:24:22.000000000 +0100
@@ -45,6 +45,7 @@
#include "exceptions.h"
#include "solib.h"
#include "filenames.h"
+#include "symspace.h"

#ifndef O_LARGEFILE
@@ -286,6 +287,7 @@ core_open (char *filename, int from_tty)
int scratch_chan;
int flags;
int corelow_pid = CORELOW_PID;
+ struct inferior *inf;

target_preopen (from_tty);
if (!filename)
@@ -371,7 +373,9 @@ core_open (char *filename, int from_tty)
push_target (&core_ops);
discard_cleanups (old_chain);

- add_inferior_silent (corelow_pid);
+ inf = add_inferior_silent (corelow_pid);
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;

/* Do this before acknowledging the inferior, so if
post_create_inferior throws (can happen easilly if you're loading
Index: src/gdb/exec.c
===================================================================
--- src.orig/gdb/exec.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/exec.c 2009-06-15 16:08:07.000000000 +0100
@@ -32,6 +32,8 @@
#include "exec.h"
#include "observer.h"
#include "arch-utils.h"
+#include "gdbthread.h"
+#include "symspace.h"

#include <fcntl.h>
#include "readline/readline.h"
@@ -66,20 +68,8 @@ void _initialize_exec (void);

struct target_ops exec_ops;

-/* The Binary File Descriptor handle for the executable file. */
-
-bfd *exec_bfd = NULL;
-long exec_bfd_mtime = 0;
-
-/* GDB currently only supports a single symbol/address space for the
- whole debug session. When that limitation is lifted, this global
- goes away. */
-static struct target_section_table current_target_sections_1;
-
-/* The set of target sections matching the sections mapped into the
- current inferior's address space. */
-static struct target_section_table *current_target_sections
- = &current_target_sections_1;
+/* True if the exec target is pushed on the stack. */
+static int using_exec_ops;

/* Whether to open exec and core files read-only or read-write. */

@@ -105,7 +95,7 @@ exec_open (char *args, int from_tty)
/* Close and clear exec_bfd. If we end up with no target sections to
read memory from, this unpushes the exec_ops target. */

-static void
+void
exec_close_1 (void)
{
if (exec_bfd)
@@ -127,12 +117,17 @@ exec_close_1 (void)
}
}

+/* This is the target_close implementation. Clears all target
+ sections and closes all executable bfds from all symbol spaces. */
+
static void
exec_close (int quitting)
{
int need_symtab_cleanup = 0;
struct vmap *vp, *nxt;

+ using_exec_ops = 0;
+
for (nxt = vmap; nxt != NULL;)
{
vp = nxt;
@@ -163,13 +158,25 @@ exec_close (int quitting)

vmap = NULL;

- /* Delete all target sections. */
- resize_section_table
- (current_target_sections,
- -resize_section_table (current_target_sections, 0));
+ {
+ struct symbol_space *ss;
+ struct cleanup *old_chain;

- /* Remove exec file. */
- exec_close_1 ();
+ old_chain = save_current_symbol_space ();
+ ALL_SSPACES (ss)
+ {
+ set_current_symbol_space (ss);
+
+ /* Delete all target sections. */
+ resize_section_table
+ (current_target_sections,
+ -resize_section_table (current_target_sections, 0));
+
+ exec_close_1 ();
+ }
+
+ do_cleanups (old_chain);
+ }
}

void
@@ -182,6 +189,20 @@ exec_file_clear (int from_tty)
printf_unfiltered (_("No executable file now.\n"));
}

+void
+exec_file_add (char *filename, int from_tty)
+{
+ struct address_space *aspace;
+ struct symbol_space *sspace;
+
+ aspace = maybe_new_address_space ();
+ sspace = add_symbol_space (aspace);
+ set_current_symbol_space (sspace);
+ switch_to_thread (null_ptid);
+ exec_file_attach (filename, from_tty);
+ sspace->name = xstrdup (lbasename (filename));
+}
+
/* Set FILENAME as the new exec file.

This function is intended to be behave essentially the same
@@ -295,7 +316,8 @@ exec_file_attach (char *filename, int fr
set_gdbarch_from_file (exec_bfd);

/* Add the executable's sections to the current address spaces'
- list of sections. */
+ list of sections. This possibly pushes the exec_ops
+ target. */
add_target_sections (sections, sections_end);
xfree (sections);

@@ -465,8 +487,11 @@ add_target_sections (struct target_secti

/* If these are the first file sections we can provide memory
from, push the file_stratum target. */
- if (space == 0)
- push_target (&exec_ops);
+ if (!using_exec_ops)
+ {
+ using_exec_ops = 1;
+ push_target (&exec_ops);
+ }
}
}

@@ -499,7 +524,16 @@ remove_target_sections (bfd *abfd)
/* If we don't have any more sections to read memory from,
remove the file_stratum target from the stack. */
if (old_count + (dest - src) == 0)
- unpush_target (&exec_ops);
+ {
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->target_sections.sections
+ != sspace->target_sections.sections_end)
+ return;
+
+ unpush_target (&exec_ops);
+ }
}
}

Index: src/gdb/exec.h
===================================================================
--- src.orig/gdb/exec.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/exec.h 2009-06-15 15:24:22.000000000 +0100
@@ -21,6 +21,7 @@
#define EXEC_H

#include "target.h"
+#include "symspace.h"

struct target_section;
struct target_ops;
@@ -28,6 +29,9 @@ struct bfd;

extern struct target_ops exec_ops;

+#define exec_bfd current_symbol_space->ebfd
+#define exec_bfd_mtime current_symbol_space->ebfd_mtime
+
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */

@@ -78,5 +82,6 @@ extern void add_target_sections (struct
extern void print_section_info (struct target_section_table *table,
bfd *abfd);

+extern void exec_close_1 (void);

#endif
Index: src/gdb/fork-child.c
===================================================================
--- src.orig/gdb/fork-child.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/fork-child.c 2009-06-15 15:24:22.000000000 +0100
@@ -138,6 +138,7 @@ fork_inferior (char *exec_file_arg, char
int shell = 0;
static char **argv;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ struct inferior *inf;

/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@@ -395,7 +396,10 @@ fork_inferior (char *exec_file_arg, char
if (!have_inferiors ())
init_thread_list ();

- add_inferior (pid);
+ inf = add_inferior (pid);
+
+ inf->aspace = current_symbol_space->aspace;
+ inf->sspace = current_symbol_space;

/* Needed for wait_for_inferior stuff below. */
inferior_ptid = pid_to_ptid (pid);
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/frame.c 2009-06-15 15:24:22.000000000 +0100
@@ -67,6 +67,9 @@ struct frame_info
moment leave this as speculation. */
int level;

+ struct symbol_space *sspace;
+ struct address_space *aspace;
+
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
for the previous frame. The low-level unwind methods are
@@ -905,10 +908,12 @@ put_frame_register_bytes (struct frame_i
/* Create a sentinel frame. */

static struct frame_info *
-create_sentinel_frame (struct regcache *regcache)
+create_sentinel_frame (struct symbol_space *sspace, struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
frame->level = -1;
+ frame->sspace = sspace;
+ frame->aspace = get_regcache_aspace (regcache);
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
@@ -990,7 +995,7 @@ get_current_frame (void)
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
- create_sentinel_frame (get_current_regcache ());
+ create_sentinel_frame (current_symbol_space, get_current_regcache ());
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
RETURN_MASK_ERROR) != 0)
{
@@ -1121,7 +1126,7 @@ create_new_frame (CORE_ADDR addr, CORE_A

fi = FRAME_OBSTACK_ZALLOC (struct frame_info);

- fi->next = create_sentinel_frame (get_current_regcache ());
+ fi->next = create_sentinel_frame (current_symbol_space, get_current_regcache ());

/* Set/update this frame's cached PC value, found in the next frame.
Do this before looking for this frame's unwinder. A sniffer is
@@ -1130,6 +1135,9 @@ create_new_frame (CORE_ADDR addr, CORE_A
fi->next->prev_pc.value = pc;
fi->next->prev_pc.p = 1;

+ fi->sspace = fi->next->sspace;
+ fi->aspace = fi->next->aspace;
+
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
@@ -1383,6 +1391,11 @@ get_prev_frame_1 (struct frame_info *thi
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;

+ /* For now, assume we don't have frame chains crossing address
+ spaces. */
+ prev_frame->sspace = this_frame->sspace;
+ prev_frame->aspace = this_frame->aspace;
+
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
@@ -1718,6 +1731,28 @@ get_frame_type (struct frame_info *frame
return frame->unwind->type;
}

+struct symbol_space *
+get_frame_symbol_space (struct frame_info *frame)
+{
+ return frame->sspace;
+}
+
+struct symbol_space *
+frame_unwind_symbol_space (struct frame_info *this_frame)
+{
+ gdb_assert (this_frame);
+
+ /* Assume for now that we don't frame chains crossing address
+ spaces. */
+ return this_frame->sspace;
+}
+
+struct address_space *
+get_frame_address_space (struct frame_info *frame)
+{
+ return frame->aspace;
+}
+
/* Memory access methods. */

void
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/frame.h 2009-06-15 15:24:22.000000000 +0100
@@ -374,6 +374,12 @@ extern int frame_relative_level (struct

extern enum frame_type get_frame_type (struct frame_info *);

+extern struct symbol_space *get_frame_symbol_space (struct frame_info *);
+
+extern struct address_space *get_frame_address_space (struct frame_info *);
+
+extern struct symbol_space *frame_unwind_symbol_space (struct frame_info *);
+
/* For frames where we can not unwind further, describe why. */

enum unwind_stop_reason
Index: src/gdb/gdbcore.h
===================================================================
--- src.orig/gdb/gdbcore.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/gdbcore.h 2009-06-15 15:24:22.000000000 +0100
@@ -28,6 +28,7 @@ struct type;
struct regcache;

#include "bfd.h"
+#include "exec.h"

/* Return the name of the executable file as a string.
ERR nonzero means get error if there is none specified;
@@ -94,13 +95,9 @@ extern void (*deprecated_file_changed_ho

extern void specify_exec_file_hook (void (*hook) (char *filename));

-/* Binary File Diddlers for the exec and core files. */
+/* Binary File Diddlers for the core file. */

extern bfd *core_bfd;
-extern bfd *exec_bfd;
-
-/* The mtime when we last opened exec_bfd. */
-extern long exec_bfd_mtime;

/* Whether to open exec and core files read-only or read-write. */

@@ -110,7 +107,7 @@ extern void core_file_command (char *fil

extern void exec_file_attach (char *filename, int from_tty);

-extern void exec_file_clear (int from_tty);
+extern void exec_file_add (char *filename, int from_tty);

extern void validate_files (void);

Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/infcmd.c 2009-06-15 15:24:22.000000000 +0100
@@ -2145,19 +2145,35 @@ attach_command_post_wait (char *args, in
exec_file = target_pid_to_exec_file (PIDGET (inferior_ptid));
if (exec_file)
{
- /* It's possible we don't have a full path, but rather just a
- filename. Some targets, such as HP-UX, don't provide the
- full path, sigh.
-
- Attempt to qualify the filename against the source path.
- (If that fails, we'll just fall back on the original
- filename. Not much more we can do...)
- */
- if (!source_full_path_of (exec_file, &full_exec_path))
- full_exec_path = xstrdup (exec_file);
+ struct gdb_exception e;

- exec_file_attach (full_exec_path, from_tty);
- symbol_file_add_main (full_exec_path, from_tty);
+ if (gdb_sysroot && *gdb_sysroot)
+ {
+ char *name = xmalloc (strlen (gdb_sysroot)
+ + strlen (exec_file)
+ + 1);
+ strcpy (name, gdb_sysroot);
+ strcat (name, exec_file);
+ full_exec_path = name;
+ }
+ else
+ {
+ /* It's possible we don't have a full path, but rather just a
+ filename. Some targets, such as HP-UX, don't provide the
+ full path, sigh.
+
+ Attempt to qualify the filename against the source path.
+ (If that fails, we'll just fall back on the original
+ filename. Not much more we can do...) */
+ if (!source_full_path_of (exec_file, &full_exec_path))
+ full_exec_path = xstrdup (exec_file);
+ }
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ exec_file_attach (full_exec_path, from_tty);
+ symbol_file_add_main (full_exec_path, from_tty);
+ }
}
}
else
@@ -2297,6 +2313,7 @@ attach_command (char *args, int from_tty

/* Set up execution context to know that we should return from
wait_for_inferior as soon as the target reports a stop. */
+
init_wait_for_inferior ();
clear_proceed_status ();

Index: src/gdb/inferior.c
===================================================================
--- src.orig/gdb/inferior.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/inferior.c 2009-06-15 15:24:22.000000000 +0100
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */

#include "defs.h"
+#include "exec.h"
#include "inferior.h"
#include "target.h"
#include "command.h"
@@ -29,7 +30,7 @@

void _initialize_inferiors (void);

-static struct inferior *inferior_list = NULL;
+struct inferior *inferior_list = NULL;
static int highest_inferior_num;

/* Print notices on inferior events (attach, detach, etc.), set with
@@ -39,7 +40,13 @@ static int print_inferior_events = 0;
struct inferior*
current_inferior (void)
{
- struct inferior *inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
+ int pid;
+ struct inferior *inf;
+
+ pid = ptid_get_pid (inferior_ptid);
+ gdb_assert (pid != 0);
+
+ inf = find_inferior_pid (pid);
gdb_assert (inf);
return inf;
}
@@ -125,11 +132,12 @@ delete_thread_of_inferior (struct thread

/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
+
static void
delete_inferior_1 (int pid, int silent)
{
struct inferior *inf, *infprev;
- struct delete_thread_of_inferior_arg arg = { pid, silent };
+ struct delete_thread_of_inferior_arg arg;

infprev = NULL;

@@ -146,7 +154,7 @@ delete_inferior_1 (int pid, int silent)
iterate_over_threads (delete_thread_of_inferior, &arg);

/* Notify the observers before removing the inferior from the list,
- so that the observers have a change to look it up. */
+ so that the observers have a chance to look it up. */
observer_notify_inferior_exit (pid);

if (infprev)
@@ -193,7 +201,7 @@ discard_all_inferiors (void)
}
}

-static struct inferior *
+struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
@@ -218,6 +226,20 @@ find_inferior_pid (int pid)
}

struct inferior *
+find_inferior_for_symbol_space (struct symbol_space *sspace)
+{
+ struct inferior *inf;
+
+ for (inf = inferior_list; inf != NULL; inf = inf->next)
+ {
+ if (inf->sspace == sspace)
+ return inf;
+ }
+
+ return NULL;
+}
+
+struct inferior *
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
void *data)
{
@@ -322,11 +344,13 @@ print_inferior (struct ui_out *uiout, in
return;
}

- old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, inf_count,
+ old_chain = make_cleanup_ui_out_table_begin_end (uiout, 5, inf_count,
"inferiors");
- ui_out_table_header (uiout, 3, ui_right, "current", "Cur");
- ui_out_table_header (uiout, 4, ui_right, "id", "Id");
- ui_out_table_header (uiout, 7, ui_right, "target-id", "PID");
+ ui_out_table_header (uiout, 1, ui_left, "current", "");
+ ui_out_table_header (uiout, 4, ui_left, "id", "Id");
+ ui_out_table_header (uiout, 17, ui_left, "target-id", "Target ID");
+ ui_out_table_header (uiout, 6, ui_left, "sspace-id", "SSpace");
+ ui_out_table_header (uiout, 17, ui_left, "exec", "Main Program");
ui_out_table_body (uiout);

for (inf = inferior_list; inf; inf = inf->next)
@@ -344,12 +368,38 @@ print_inferior (struct ui_out *uiout, in
ui_out_field_skip (uiout, "current");

ui_out_field_int (uiout, "id", inf->num);
- ui_out_field_int (uiout, "target-id", inf->pid);
+ ui_out_field_string (uiout, "target-id",
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+
+ ui_out_field_int (uiout, "sspace-id", inf->sspace->num);
+
+ if (inf->sspace->ebfd)
+ ui_out_field_string (uiout, "exec",
+ bfd_get_filename (inf->sspace->ebfd));
+ else
+ ui_out_field_skip (uiout, "exec");
+
+ if (inf->vfork_parent)
+ {
+ ui_out_text (uiout, _("\n\tis vfork child of inferior "));
+ ui_out_field_int (uiout, "vfork-parent", inf->vfork_parent->num);
+ }
+
+ if (inf->vfork_child)
+ {
+ ui_out_text (uiout, _("\n\tis vfork parent of inferior "));
+ ui_out_field_int (uiout, "vfork-child", inf->vfork_child->num);
+ }

ui_out_text (uiout, "\n");
do_cleanups (chain2);
}

+ if (inferior_list
+ && ptid_equal (inferior_ptid, null_ptid))
+ ui_out_message (uiout, 0, "\n\
+No selected inferior/thread. See `help thread' or `help inferior'.\n");
+
do_cleanups (old_chain);
}

Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/inferior.h 2009-06-15 15:24:22.000000000 +0100
@@ -41,6 +41,9 @@ struct terminal_info;
/* For struct frame_id. */
#include "frame.h"

+/* For current_symbol_space. */
+#include "symspace.h"
+
/* Two structures are used to record inferior state.

inferior_thread_state contains state about the program itself like its
@@ -149,6 +152,11 @@ extern int step_stop_if_no_debug;
are kept running freely. */
extern int non_stop;

+/* If set (default), when following a fork, GDB will detach from one
+ the fork branches, child or parent. Exactly which branch is
+ detached depends on 'set follow-fork-mode' setting. */
+extern int detach_fork;
+
extern void generic_mourn_inferior (void);

extern void terminal_save_ours (void);
@@ -401,6 +409,12 @@ struct inferior
the ptid_t.pid member of threads of this inferior. */
int pid;

+ /* The address space bound to this inferior. */
+ struct address_space *aspace;
+
+ /* The symbol space bound to this inferior. */
+ struct symbol_space *sspace;
+
/* See the definition of stop_kind above. */
enum stop_kind stop_soon;

@@ -408,6 +422,14 @@ struct inferior
forked. */
int attach_flag;

+ struct inferior *vfork_parent;
+
+ /* A vfork parent is left stopped by the kernel until the child
+ execs or exits, so a process can only have one vfork child. */
+ struct inferior *vfork_child;
+
+ int pending_detach;
+
/* What is left to do for an execution command after any thread of
this inferior stops. For continuations associated with a
specific thread, see `struct thread_info'. */
@@ -461,9 +483,16 @@ extern int in_inferior_list (int pid);
not the system's). */
extern int valid_gdb_inferior_id (int num);

-/* Search function to lookup a inferior by target 'pid'. */
+/* Search function to lookup an inferior by target 'pid'. */
extern struct inferior *find_inferior_pid (int pid);

+/* Search function to lookup an inferior by GDB 'num'. */
+extern struct inferior *find_inferior_id (int num);
+
+/* Find an inferior bound to SSPACE. */
+extern struct inferior *
+ find_inferior_for_symbol_space (struct symbol_space *sspace);
+
/* Inferior iterator function.

Calls a callback function once for each inferior, so long as the
@@ -495,4 +524,6 @@ extern int have_live_inferiors (void);
this if there is no current inferior. */
extern struct inferior *current_inferior (void);

+extern struct inferior *inferior_list;
+
#endif /* !defined (INFERIOR_H) */
Index: src/gdb/inf-ptrace.c
===================================================================
--- src.orig/gdb/inf-ptrace.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/inf-ptrace.c 2009-06-15 15:24:22.000000000 +0100
@@ -226,6 +226,8 @@ inf_ptrace_attach (struct target_ops *op
inferior_ptid = pid_to_ptid (pid);

inf = add_inferior (pid);
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
inf->attach_flag = 1;

/* Always add a main thread. If some target extends the ptrace
Index: src/gdb/linespec.c
===================================================================
--- src.orig/gdb/linespec.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/linespec.c 2009-06-15 15:24:22.000000000 +0100
@@ -1599,6 +1599,8 @@ decode_all_digits (char **argptr, struct

init_sal (&val);

+ val.sspace = current_symbol_space;
+
/* This is where we need to make sure that we have good defaults.
We must guarantee that this section of code is never executed
when we are called with just a function name, since
@@ -1650,6 +1652,7 @@ decode_all_digits (char **argptr, struct
if (val.symtab == 0)
val.symtab = file_symtab;

+ val.sspace = SYMTAB_SSPACE (val.symtab);
val.pc = 0;
values.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
@@ -1721,6 +1724,7 @@ decode_dollar (char *copy, int funfirstl
val.symtab = file_symtab ? file_symtab : default_symtab;
val.line = valx;
val.pc = 0;
+ val.sspace = current_symbol_space;

values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
values.sals[0] = val;
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c 2009-06-15 15:24:19.000000000 +0100
+++ src/gdb/linux-nat.c 2009-06-15 15:24:22.000000000 +0100
@@ -54,6 +54,7 @@
#include "gdb_dirent.h"
#include "xml-support.h"
#include "terminal.h"
+#include "solib.h"

#ifdef HAVE_PERSONALITY
# include <sys/personality.h>
@@ -613,22 +614,26 @@ the child run until it execs or exits, a

if (! follow_child)
{
- /* We're already attached to the parent, by default. */
+ struct lwp_info *child_lp = NULL;

- /* Before detaching from the child, remove all breakpoints from
- it. If we forked, then this has already been taken care of
- by infrun.c. If we vforked however, any breakpoint inserted
- in the parent is visible in the child, even those added while
- stopped in a vfork catchpoint. This won't actually modify
- the breakpoint list, but will physically remove the
- breakpoints from the child. This will remove the breakpoints
- from the parent also, but they'll be reinserted below. */
- if (has_vforked)
- detach_breakpoints (child_pid);
+ /* We're already attached to the parent, by default. */

/* Detach new forked process? */
if (detach_fork)
{
+ /* Before detaching from the child, remove all breakpoints
+ from it. If we forked, then this has already been taken
+ care of by infrun.c. If we vforked however, any
+ breakpoint inserted in the parent is visible in the
+ child, even those added while stopped in a vfork
+ catchpoint. This will remove the breakpoints from the
+ parent also, but they'll be reinserted below. */
+ if (has_vforked)
+ {
+ /* keep breakpoints list in sync. */
+ remove_breakpoints_pid (GET_PID (inferior_ptid));
+ }
+
if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
@@ -642,7 +647,6 @@ the child run until it execs or exits, a
else
{
struct inferior *parent_inf, *child_inf;
- struct lwp_info *lp;
struct cleanup *old_chain;

/* Add process to GDB's tables. */
@@ -653,12 +657,47 @@ the child run until it execs or exits, a
copy_terminal_info (child_inf, parent_inf);

old_chain = save_inferior_ptid ();
+ save_current_symbol_space ();

inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
- lp = add_lwp (inferior_ptid);
- lp->stopped = 1;
+ child_lp = add_lwp (inferior_ptid);
+ child_lp->stopped = 1;
+ child_lp->resumed = 1;
+
+ /* If this is a vfork child, then the address-space is
+ shared with the parent. */
+ if (has_vforked)
+ {
+ child_inf->sspace = parent_inf->sspace;
+ child_inf->aspace = parent_inf->aspace;
+
+ /* The parent will be frozen until the child is done
+ with the shared region. Keep track of the
+ parent. */
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = 0;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->sspace = add_symbol_space (child_inf->aspace);
+ child_inf->sspace->removable = 1;
+ set_current_symbol_space (child_inf->sspace);
+ clone_symbol_space (child_inf->sspace, parent_inf->sspace);
+
+ /* Let the shared library layer (solib-svr4) learn about
+ this new process, relocate the cloned exec, pull in
+ shared libraries, and install the solib event
+ breakpoint. If a "cloned-VM" event was propagated
+ better throughout the core, this wouldn't be
+ required. */
+ solib_create_inferior_hook ();
+ }

+ /* Let the thread_db layer learn about this new process. */
check_for_thread_db ();

do_cleanups (old_chain);
@@ -666,16 +705,22 @@ the child run until it execs or exits, a

if (has_vforked)
{
+ struct lwp_info *lp;
+
+ lp = find_lwp_pid (pid_to_ptid (parent_pid));
gdb_assert (linux_supports_tracefork_flag >= 0);
- if (linux_supports_tracevforkdone (0))
+ if (1 && linux_supports_tracevforkdone (0))
{
- int status;
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LCFF: waiting for VFORK_DONE on %d\n",
+ parent_pid);
+
+ lp->stopped = 1;
+ lp->resumed = 1;

- ptrace (PTRACE_CONT, parent_pid, 0, 0);
- my_waitpid (parent_pid, &status, __WALL);
- if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
- warning (_("Unexpected waitpid result %06x when waiting for "
- "vfork-done"), status);
+ /* We'll handle the VFORK_DONE event like any other
+ event, in target_wait. */
}
else
{
@@ -711,11 +756,20 @@ the child run until it execs or exits, a
point. */

usleep (10000);
- }

- /* Since we vforked, breakpoints were removed in the parent
- too. Put them back. */
- reattach_breakpoints (parent_pid);
+ /* Pretend we've seen a PTRACE_EVENT_VFORK_DONE event,
+ and leave it pending. The next linux_nat_resume call
+ will notice a pending event, and bypasses actually
+ resuming the inferior. */
+ lp->status = SIGTRAP | (PTRACE_EVENT_VFORK_DONE << 16);
+ lp->stopped = 0;
+ lp->resumed = 1;
+
+ /* If we're in async mode, need to tell the event loop
+ there's something here to process. */
+ if (target_can_async_p ())
+ async_file_mark ();
+ }
}
}
else
@@ -723,16 +777,19 @@ the child run until it execs or exits, a
struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
-
- /* Before detaching from the parent, remove all breakpoints from it. */
- remove_breakpoints ();
+ struct symbol_space *parent_sspace;

if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
- fprintf_filtered (gdb_stdlog,
- "Attaching after fork to child process %d.\n",
- child_pid);
+ if (has_vforked)
+ fprintf_filtered (gdb_stdlog, _("\
+Attaching after process %d vfork to child process %d.\n"),
+ parent_pid, child_pid);
+ else
+ fprintf_filtered (gdb_stdlog, _("\
+Attaching after process %d fork to child process %d.\n"),
+ parent_pid, child_pid);
}

/* Add the new inferior first, so that the target_detach below
@@ -744,53 +801,67 @@ the child run until it execs or exits, a
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);

- /* If we're vforking, we may want to hold on to the parent until
- the child exits or execs. At exec time we can remove the old
- breakpoints from the parent and detach it; at exit time we
- could do the same (or even, sneakily, resume debugging it - the
- child's exec has failed, or something similar).
-
- This doesn't clean up "properly", because we can't call
- target_detach, but that's OK; if the current target is "child",
- then it doesn't need any further cleanups, and lin_lwp will
- generally not encounter vfork (vfork is defined to fork
- in libpthread.so).
-
- The holding part is very easy if we have VFORKDONE events;
- but keeping track of both processes is beyond GDB at the
- moment. So we don't expose the parent to the rest of GDB.
- Instead we quietly hold onto it until such time as we can
- safely resume it. */
+ parent_sspace = parent_inf->sspace;
+
+ /* If we're vforking, we want to hold on to the parent until the
+ child exits or execs. At child exec or exit time we can
+ remove the old breakpoints from the parent and detach or
+ resume it. Otherwise, detach the parent now; we'll want to
+ reuse it's symbol/address spaces, but we can't set them to
+ the child before removing breakpoints from the parent,
+ otherwise, the breakpoints module could decide to remove
+ breakpoints from the wrong process (since they'd be assigned
+ to the same address space). */

if (has_vforked)
{
- struct lwp_info *parent_lwp;
-
- linux_parent_pid = parent_pid;
-
- /* Get rid of the inferior on the core side as well. */
- inferior_ptid = null_ptid;
- detach_inferior (parent_pid);
-
- /* Also get rid of all its lwps. We will detach from this
- inferior soon-ish, but, we will still get an exit event
- reported through waitpid when it exits. If we didn't get
- rid of the lwps from our list, we would end up reporting
- the inferior exit to the core, which would then try to
- mourn a non-existing (from the core's perspective)
- inferior. */
- parent_lwp = find_lwp_pid (pid_to_ptid (parent_pid));
- purge_lwp_list (GET_PID (parent_lwp->ptid));
- linux_parent_pid = parent_pid;
+ gdb_assert (child_inf->vfork_parent == NULL);
+ gdb_assert (parent_inf->vfork_child == NULL);
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = detach_fork;
}
else if (detach_fork)
target_detach (NULL, 0);

+ /* Note that the detach above makes PARENT_INF dangling. */
+
+ /* Add the child thread to the appropriate lists, and switch to
+ this new thread, before cloning the symbol space, and
+ informing the solib layer about this new process. */
+
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
+ lp->resumed = 1;
+
+ /* If this is a vfork child, then the address-space is shared
+ with the parent. If we detached from the parent, then we can
+ reuse the parent's symbol/address spaces. */
+ if (has_vforked || detach_fork)
+ {
+ child_inf->sspace = parent_sspace;
+ child_inf->aspace = child_inf->sspace->aspace;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->sspace = add_symbol_space (child_inf->aspace);
+ child_inf->sspace->removable = 1;
+ set_current_symbol_space (child_inf->sspace);
+ clone_symbol_space (child_inf->sspace, parent_sspace);
+
+ /* Let the shared library layer (solib-svr4) learn about
+ this new process, relocate the cloned exec, pull in
+ shared libraries, and install the solib event breakpoint.
+ If a "cloned-VM" event was propagated better throughout
+ the core, this wouldn't be required. */
+ solib_create_inferior_hook ();
+ }

+ /* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
}

@@ -1622,7 +1693,12 @@ linux_nat_detach (struct target_ops *ops
static int
resume_callback (struct lwp_info *lp, void *data)
{
- if (lp->stopped && lp->status == 0)
+ struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
+
+ if (lp->stopped && inf->vfork_child != NULL)
+ fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (vfork parent)\n",
+ target_pid_to_str (lp->ptid));
+ else if (lp->stopped && lp->status == 0)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -1971,25 +2047,25 @@ linux_handle_extended_wait (struct lwp_i
ourstatus->value.execd_pathname
= xstrdup (linux_child_pid_to_exec_file (pid));

- if (linux_parent_pid)
- {
- detach_breakpoints (linux_parent_pid);
- ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
+ return 0;
+ }

- linux_parent_pid = 0;
- }
+ if (event == PTRACE_EVENT_VFORK_DONE)
+ {
+ /* Done with the shared memory region. Re-insert breakpoints in
+ the parent, and keep waiting. */
+ struct thread_info *tp;

- /* At this point, all inserted breakpoints are gone. Doing this
- as soon as we detect an exec prevents the badness of deleting
- a breakpoint writing the current "shadow contents" to lift
- the bp. That shadow is NOT valid after an exec.
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LHEW: Got PTRACE_EVENT_VFORK_DONE from LWP %ld\n",
+ GET_LWP (lp->ptid));

- Note that we have to do this after the detach_breakpoints
- call above, otherwise breakpoints wouldn't be lifted from the
- parent on a vfork, because detach_breakpoints would think
- that breakpoints are not inserted. */
- mark_breakpoints_out ();
- return 0;
+ tp = any_live_thread_of_process (GET_PID (lp->ptid));
+ switch_to_thread (tp->ptid);
+ insert_breakpoints ();
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ return 1;
}

internal_error (__FILE__, __LINE__,
@@ -2179,6 +2255,13 @@ maybe_clear_ignore_sigint (struct lwp_in
static int
stop_wait_callback (struct lwp_info *lp, void *data)
{
+ struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
+
+ /* If this is a vfork parent, bail out, it is not going to report
+ any SIGSTOP until the vfork is done with. */
+ if (inf->vfork_child != NULL)
+ return 0;
+
if (!lp->stopped)
{
int status;
@@ -2402,7 +2485,7 @@ cancel_breakpoint (struct lwp_info *lp)
CORE_ADDR pc;

pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
- if (breakpoint_inserted_here_p (pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -3355,6 +3438,7 @@ linux_nat_xfer_partial (struct target_op
{
struct cleanup *old_chain;
LONGEST xfer;
+ struct lwp_info *lp = NULL;

if (object == TARGET_OBJECT_SIGNAL_INFO)
return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf,
@@ -3368,6 +3452,78 @@ linux_nat_xfer_partial (struct target_op

old_chain = save_inferior_ptid ();

+ if (0 && object == TARGET_OBJECT_MEMORY)
+ {
+ int pid;
+ ptid_t ptid;
+ struct lwp_info *any = NULL;
+
+ pid = GET_PID (inferior_ptid);
+
+ /* When following a fork, we'll call detach_breakpoints
+ (child_pid), without child_pid being listed in the lwp list.
+ Assume that if no lwp matching PID is found, than
+ inferior_ptid is already set correctly to a stopped lwp. */
+ ALL_LWPS (lp, ptid)
+ if (lp->stopped && GET_PID (lp->ptid) == pid)
+ break;
+ else if (GET_PID (lp->ptid) == pid)
+ any = lp;
+
+ if (lp)
+ {
+ inferior_ptid = lp->ptid;
+ lp = NULL; /* No need to resume. */
+ }
+ else if (any)
+ {
+ do
+ {
+ struct inferior *inf;
+
+ ALL_LWPS (lp, ptid)
+ if (GET_PID (lp->ptid) == pid)
+ break;
+
+ /* The whole process is gone, nothing we can do. */
+ if (lp == NULL)
+ {
+ do_cleanups (old_chain);
+ errno = ESRCH;
+ return 1;
+ }
+
+ inf = find_inferior_pid (pid);
+
+ /* This this is a vfork parent, is it already
+ stopped. */
+
+ /* FIXME: Is this really needed? It is here because a
+ vfork parent lwp can sometimes be !lp->stopped. */
+ if (inf->vfork_child != NULL)
+ {
+ inferior_ptid = lp->ptid;
+ lp = NULL;
+ break;
+ }
+
+ stop_callback (lp, NULL);
+ stop_wait_callback (lp, NULL);
+
+ /* If the lwp exits while we try to stop it, there's
+ nothing else to do. */
+ lp = find_lwp_pid (ptid);
+
+ /* We should never delete the main lwp though. */
+ gdb_assert (num_lwps (pid) > 0);
+ }
+ while (lp == NULL);
+
+ if (lp)
+ inferior_ptid = lp->ptid;
+ }
+ }
+
if (is_lwp (inferior_ptid))
inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));

@@ -3375,6 +3531,13 @@ linux_nat_xfer_partial (struct target_op
offset, len);

do_cleanups (old_chain);
+
+ if (lp)
+ {
+ resume_callback (lp, NULL);
+ resume_set_callback (lp, NULL);
+ }
+
return xfer;
}

Index: src/gdb/linux-thread-db.c
===================================================================
--- src.orig/gdb/linux-thread-db.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/linux-thread-db.c 2009-06-15 15:24:22.000000000 +0100
@@ -1201,18 +1201,15 @@ thread_db_wait (struct target_ops *ops,

if (ourstatus->kind == TARGET_WAITKIND_EXECD)
{
- /* Breakpoints have already been marked non-inserted by the
- layer below. We're safe in knowing that removing them will
- not write the shadows of the old image into the new
- image. */
- remove_thread_event_breakpoints ();
-
/* New image, it may or may not end up using thread_db. Assume
not unless we find otherwise. */
delete_thread_db_info (GET_PID (ptid));
if (!thread_db_list)
unpush_target (&thread_db_ops);

+ /* Thread event breakpoints are deleted by
+ update_breakpoints_after_exec. */
+
return ptid;
}

@@ -1249,13 +1246,12 @@ thread_db_mourn_inferior (struct target_

delete_thread_db_info (GET_PID (inferior_ptid));

- /* Delete the old thread event breakpoints. Mark breakpoints out,
- so that we don't try to un-insert them. */
- mark_breakpoints_out ();
- remove_thread_event_breakpoints ();
-
target_beneath->to_mourn_inferior (target_beneath);

+ /* Delete the old thread event breakpoints. Do this after mourning
+ the inferior, so that we don't try to uninsert them. */
+ remove_thread_event_breakpoints ();
+
/* Detach thread_db target ops. */
if (!thread_db_list)
unpush_target (ops);
Index: src/gdb/objfiles.c
===================================================================
--- src.orig/gdb/objfiles.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/objfiles.c 2009-06-15 15:24:22.000000000 +0100
@@ -59,9 +59,7 @@ static void objfile_free_data (struct ob
/* Externally visible variables that are owned by this module.
See declarations in objfile.h for more info. */

-struct objfile *object_files; /* Linked list of all objfiles */
struct objfile *current_objfile; /* For symbol file being read in */
-struct objfile *symfile_objfile; /* Main symbol table loaded from */
struct objfile *rt_common_objfile; /* For runtime common symbols */

/* Locate all mappable sections of a BFD file.
@@ -201,6 +199,8 @@ allocate_objfile (bfd *abfd, int flags)
objfile->name = xstrdup ("<<anonymous objfile>>");
}

+ objfile->sspace = current_symbol_space;
+
/* Initialize the section indexes for this objfile, so that we can
later detect if they are used w/o being properly assigned to. */

Index: src/gdb/objfiles.h
===================================================================
--- src.orig/gdb/objfiles.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/objfiles.h 2009-06-15 15:24:22.000000000 +0100
@@ -23,11 +23,13 @@

#include "gdb_obstack.h" /* For obstack internals. */
#include "symfile.h" /* For struct psymbol_allocation_list */
+#include "symspace.h"

struct bcache;
struct htab;
struct symtab;
struct objfile_data;
+struct symbol_space;

/* This structure maintains information on a per-objfile basis about the
"entry point" of the objfile, and the scope within which the entry point
@@ -200,6 +202,10 @@ struct objfile

unsigned short flags;

+ /* The symbol space associated with this objfile. */
+
+ struct symbol_space *sspace;
+
/* Each objfile points to a linked list of symtabs derived from this file,
one symtab structure for each compilation unit (source file). Each link
in the symtab list contains a backpointer to this objfile. */
@@ -419,12 +425,6 @@ struct objfile

#define OBJF_KEEPBFD (1 << 4) /* Do not delete bfd */

-
-/* The object file that the main symbol table was loaded from (e.g. the
- argument to the "symbol-file" or "file" command). */
-
-extern struct objfile *symfile_objfile;
-
/* The object file that contains the runtime common minimal symbols
for SunOS4. Note that this objfile has no associated BFD. */

@@ -445,11 +445,6 @@ extern struct objfile *rt_common_objfile

extern struct objfile *current_objfile;

-/* All known objfiles are kept in a linked list. This points to the
- root of this list. */
-
-extern struct objfile *object_files;
-
/* Declarations for functions defined in objfiles.c */

extern struct objfile *allocate_objfile (bfd *, int);
@@ -510,14 +505,27 @@ extern void *objfile_data (struct objfil
const struct objfile_data *data);
\f

-/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete
- the objfile during the traversal. */
+/* Traverse all object files in the current symbol space.
+ ALL_OBJFILES_SAFE works even if you delete the objfile during the
+ traversal. */
+
+/* Traverse all object files in symbol space SS. */
+
+#define ALL_SSPACE_OBJFILES(ss, obj) \
+ for ((obj) = ss->objfiles; (obj) != NULL; (obj) = (obj)->next) \

-#define ALL_OBJFILES(obj) \
- for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next)
+#define ALL_SSPACE_OBJFILES_SAFE(ss, obj, nxt) \
+ for ((obj) = ss->objfiles; \
+ (obj) != NULL? ((nxt)=(obj)->next,1) :0; \
+ (obj) = (nxt))
+
+#define ALL_OBJFILES(obj) \
+ for ((obj) = current_symbol_space->objfiles; \
+ (obj) != NULL; \
+ (obj) = (obj)->next)

-#define ALL_OBJFILES_SAFE(obj,nxt) \
- for ((obj) = object_files; \
+#define ALL_OBJFILES_SAFE(obj,nxt) \
+ for ((obj) = current_symbol_space->objfiles; \
(obj) != NULL? ((nxt)=(obj)->next,1) :0; \
(obj) = (nxt))

@@ -536,27 +544,44 @@ extern void *objfile_data (struct objfil
#define ALL_OBJFILE_MSYMBOLS(objfile, m) \
for ((m) = (objfile) -> msymbols; SYMBOL_LINKAGE_NAME(m) != NULL; (m)++)

-/* Traverse all symtabs in all objfiles. */
+/* Traverse all symtabs in all objfiles in the current symbol
+ space. */

#define ALL_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s)

-/* Traverse all symtabs in all objfiles, skipping included files
- (which share a blockvector with their primary symtab). */
+#define ALL_SSPACE_SYMTABS(ss, objfile, s) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s)
+
+/* Traverse all symtabs in all objfiles in the current symbol space,
+ skipping included files (which share a blockvector with their
+ primary symtab). */

#define ALL_PRIMARY_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s) \
if ((s)->primary)

-/* Traverse all psymtabs in all objfiles. */
+#define ALL_SSPACE_PRIMARY_SYMTABS(sspace, objfile, s) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s) \
+ if ((s)->primary)
+
+/* Traverse all psymtabs in all objfiles in the current symbol
+ space. */

#define ALL_PSYMTABS(objfile, p) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)

-/* Traverse all minimal symbols in all objfiles. */
+#define ALL_SSPACE_PSYMTABS(ss, objfile, p) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+
+/* Traverse all minimal symbols in all objfiles in the current symbol
+ space. */

#define ALL_MSYMBOLS(objfile, m) \
ALL_OBJFILES (objfile) \
Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/remote.c 2009-06-15 15:24:22.000000000 +0100
@@ -1179,6 +1179,23 @@ remote_add_inferior (int pid, int attach

inf->attach_flag = attached;

+ inf->sspace = current_symbol_space;
+
+ if (gdbarch_has_global_solist (target_gdbarch))
+ {
+ /* If the target shares code across all inferiors, then every
+ inferior will use the same symbol space. However, each
+ inferior may still have its own address space. */
+ inf->aspace = maybe_new_address_space ();
+ }
+ else
+ {
+ /* In the traditional debugging scenario, there's a 1-1 match
+ between symbol/address spaces. We simply bind the inferior
+ to the symbol space's address space. */
+ inf->aspace = inf->sspace->aspace;
+ }
+
return inf;
}

@@ -2638,6 +2655,10 @@ remote_start_remote (struct ui_out *uiou
this before anything involving memory or registers. */
target_find_description ();

+ /* Next, now that we know something about the target, update the
+ address spaces in the symbol spaces. */
+ update_address_spaces ();
+
/* On OSs where the list of libraries is global to all
processes, we fetch them early. */
if (gdbarch_has_global_solist (target_gdbarch))
@@ -6759,11 +6780,14 @@ extended_remote_create_inferior_1 (char
extended_remote_restart ();
}

- /* Clean up from the last time we ran, before we mark the target
- running again. This will mark breakpoints uninserted, and
- get_offsets may insert breakpoints. */
- init_thread_list ();
- init_wait_for_inferior ();
+ if (!have_inferiors ())
+ {
+ /* Clean up from the last time we ran, before we mark the target
+ running again. This will mark breakpoints uninserted, and
+ get_offsets may insert breakpoints. */
+ init_thread_list ();
+ init_wait_for_inferior ();
+ }

/* Now mark the inferior as running before we do anything else. */
inferior_ptid = magic_null_ptid;
Index: src/gdb/solib.c
===================================================================
--- src.orig/gdb/solib.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/solib.c 2009-06-15 15:24:22.000000000 +0100
@@ -85,9 +85,8 @@ set_solib_ops (struct gdbarch *gdbarch,
configuration needs to call set_solib_ops. */
struct target_so_ops *current_target_so_ops;

-/* local data declarations */
-
-static struct so_list *so_list_head; /* List of known shared objects */
+/* List of known shared objects */
+#define so_list_head current_symbol_space->so_list

/* Local function prototypes */

@@ -871,11 +870,11 @@ solib_contains_address_p (const struct s
*/

char *
-solib_name_from_address (CORE_ADDR address)
+solib_name_from_address (struct symbol_space *sspace, CORE_ADDR address)
{
- struct so_list *so = 0; /* link map state variable */
+ struct so_list *so = NULL;

- for (so = so_list_head; so; so = so->next)
+ for (so = sspace->so_list; so; so = so->next)
if (solib_contains_address_p (so, address))
return (so->so_name);

Index: src/gdb/source.c
===================================================================
--- src.orig/gdb/source.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/source.c 2009-06-15 15:24:22.000000000 +0100
@@ -91,6 +91,8 @@ static struct symtab *current_source_sym

static int current_source_line;

+static struct symbol_space *current_source_sspace;
+
/* Default number of lines to print with commands like "list".
This is based on guessing how many long (i.e. more than chars_per_line
characters) lines there will be. To be completely correct, "list"
@@ -151,6 +153,7 @@ get_current_source_symtab_and_line (void
{
struct symtab_and_line cursal = { 0 };

+ cursal.sspace = current_source_sspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
cursal.pc = 0;
@@ -189,15 +192,17 @@ struct symtab_and_line
set_current_source_symtab_and_line (const struct symtab_and_line *sal)
{
struct symtab_and_line cursal = { 0 };
-
+
+ cursal.sspace = current_source_sspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
+ cursal.pc = 0;
+ cursal.end = 0;

+ current_source_sspace = sal->sspace;
current_source_symtab = sal->symtab;
current_source_line = sal->line;
- cursal.pc = 0;
- cursal.end = 0;
-
+
return cursal;
}

@@ -231,6 +236,7 @@ select_source_symtab (struct symtab *s)
{
current_source_symtab = s;
current_source_line = 1;
+ current_source_sspace = SYMTAB_SSPACE (s);
return;
}

@@ -244,6 +250,7 @@ select_source_symtab (struct symtab *s)
sals = decode_line_spec (main_name (), 1);
sal = sals.sals[0];
xfree (sals.sals);
+ current_source_sspace = sal.sspace;
current_source_symtab = sal.symtab;
current_source_line = max (sal.line - (lines_to_list - 1), 1);
if (current_source_symtab)
@@ -255,7 +262,7 @@ select_source_symtab (struct symtab *s)

current_source_line = 1;

- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES (ofp)
{
for (s = ofp->symtabs; s; s = s->next)
{
@@ -263,15 +270,19 @@ select_source_symtab (struct symtab *s)
int len = strlen (name);
if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
|| strcmp (name, "<<C++-namespaces>>") == 0)))
- current_source_symtab = s;
+ {
+ current_source_sspace = current_symbol_space;
+ current_source_symtab = s;
+ }
}
}
+
if (current_source_symtab)
return;

/* How about the partial symbol tables? */

- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES (ofp)
{
for (ps = ofp->psymtabs; ps != NULL; ps = ps->next)
{
@@ -292,6 +303,7 @@ select_source_symtab (struct symtab *s)
}
else
{
+ current_source_sspace = current_symbol_space;
current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
}
}
@@ -316,11 +328,13 @@ show_directories (char *ignore, int from
void
forget_cached_source_info (void)
{
+ struct symbol_space *sspace;
struct symtab *s;
struct objfile *objfile;
struct partial_symtab *pst;

- for (objfile = object_files; objfile != NULL; objfile = objfile->next)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
for (s = objfile->symtabs; s != NULL; s = s->next)
{
Index: src/gdb/symfile.c
===================================================================
--- src.orig/gdb/symfile.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/symfile.c 2009-06-15 15:24:22.000000000 +0100
@@ -2799,7 +2799,7 @@ clear_symtab_users (void)

clear_displays ();
breakpoint_re_set ();
- set_default_breakpoint (0, 0, 0, 0);
+ set_default_breakpoint (0, NULL, 0, 0, 0);
clear_pc_function_cache ();
observer_notify_new_objfile (NULL);

Index: src/gdb/symmisc.c
===================================================================
--- src.orig/gdb/symmisc.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/symmisc.c 2009-06-15 15:24:22.000000000 +0100
@@ -23,6 +23,7 @@
#include "symtab.h"
#include "gdbtypes.h"
#include "bfd.h"
+#include "exec.h"
#include "symfile.h"
#include "objfiles.h"
#include "breakpoint.h"
@@ -128,10 +129,12 @@ free_symtab (struct symtab *s)
void
print_symbol_bcache_statistics (void)
{
+ struct symbol_space *sspace;
struct objfile *objfile;

immediate_quit++;
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
printf_filtered (_("Byte cache statistics for '%s':\n"), objfile->name);
print_bcache_statistics (objfile->psymbol_cache, "partial symbol cache");
@@ -143,13 +146,15 @@ print_symbol_bcache_statistics (void)
void
print_objfile_statistics (void)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
struct symtab *s;
struct partial_symtab *ps;
int i, linetables, blockvectors;

immediate_quit++;
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
printf_filtered (_("Statistics for '%s':\n"), objfile->name);
if (OBJSTAT (objfile, n_stabs) > 0)
@@ -213,8 +218,14 @@ dump_objfile (struct objfile *objfile)
gdb_print_host_address (objfile, gdb_stdout);
printf_filtered (", bfd at ");
gdb_print_host_address (objfile->obfd, gdb_stdout);
- printf_filtered (", %d minsyms\n\n",
+ printf_filtered (", %d minsyms\n",
objfile->minimal_symbol_count);
+ if (objfile->sspace->ebfd)
+ printf_filtered (" Exec file %s",
+ bfd_get_filename (objfile->sspace->ebfd));
+ else
+ printf_filtered (" (No exec file)");
+ printf_filtered ("\n\n");

if (objfile->psymtabs)
{
@@ -869,6 +880,7 @@ maintenance_print_msymbols (char *args,
struct cleanup *cleanups;
char *filename = DEV_TTY;
char *symname = NULL;
+ struct symbol_space *sspace;
struct objfile *objfile;

struct stat sym_st, obj_st;
@@ -904,10 +916,11 @@ maintenance_print_msymbols (char *args,
make_cleanup_ui_file_delete (outfile);

immediate_quit++;
- ALL_OBJFILES (objfile)
- if (symname == NULL
- || (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
- dump_msymbols (objfile, outfile);
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ if (symname == NULL
+ || (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
+ dump_msymbols (objfile, outfile);
immediate_quit--;
fprintf_filtered (outfile, "\n\n");
do_cleanups (cleanups);
@@ -916,13 +929,22 @@ maintenance_print_msymbols (char *args,
void
maintenance_print_objfiles (char *ignore, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;

dont_repeat ();

immediate_quit++;
- ALL_OBJFILES (objfile)
- dump_objfile (objfile);
+ ALL_SSPACES (sspace)
+ {
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ dump_objfile (objfile);
+ printf_filtered ("Symfile_objfile is %s, at ",
+ (sspace->symfile_objfile_1
+ ? sspace->symfile_objfile_1->name : "(null)"));
+ gdb_print_host_address (sspace->symfile_objfile_1, gdb_stdout);
+ }
+ printf_filtered ("\n");
immediate_quit--;
}

@@ -931,12 +953,14 @@ maintenance_print_objfiles (char *ignore
void
maintenance_info_symtabs (char *regexp, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;

if (regexp)
re_comp (regexp);

- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
struct symtab *symtab;

@@ -988,12 +1012,14 @@ maintenance_info_symtabs (char *regexp,
void
maintenance_info_psymtabs (char *regexp, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;

if (regexp)
re_comp (regexp);

- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
struct partial_symtab *psymtab;

Index: src/gdb/symtab.c
===================================================================
--- src.orig/gdb/symtab.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/symtab.c 2009-06-15 15:24:22.000000000 +0100
@@ -693,6 +693,7 @@ symbol_search_name (const struct general
void
init_sal (struct symtab_and_line *sal)
{
+ sal->sspace = NULL;
sal->symtab = 0;
sal->section = 0;
sal->line = 0;
@@ -1994,9 +1995,12 @@ find_pc_sect_symtab (CORE_ADDR pc, struc
struct symtab *best_s = NULL;
struct partial_symtab *ps;
struct objfile *objfile;
+ struct symbol_space *sspace;
CORE_ADDR distance = 0;
struct minimal_symbol *msymbol;

+ sspace = current_symbol_space;
+
/* If we know that this is not a text address, return failure. This is
necessary because we loop based on the block's high and low code
addresses, which do not include the data ranges, and because
@@ -2152,6 +2156,8 @@ find_pc_sect_line (CORE_ADDR pc, struct

init_sal (&val); /* initialize to zeroes */

+ val.sspace = current_symbol_space;
+
/* It's tempting to assume that, if we can't find debugging info for
any function enclosing PC, that we shouldn't search for line
number info, either. However, GAS can emit line number info for
@@ -2651,10 +2657,14 @@ find_function_start_sal (struct symbol *
struct block *block = SYMBOL_BLOCK_VALUE (sym);
struct objfile *objfile = lookup_objfile_from_block (block);
struct gdbarch *gdbarch = get_objfile_arch (objfile);
-
+ struct cleanup *old_chain;
CORE_ADDR pc;
struct symtab_and_line sal;

+ old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (objfile->sspace);
+
pc = BLOCK_START (block);
fixup_symbol_section (sym, objfile);
if (funfirstline)
@@ -2706,7 +2716,9 @@ find_function_start_sal (struct symbol *
}

sal.pc = pc;
+ sal.sspace = objfile->sspace;

+ do_cleanups (old_chain);
return sal;
}

@@ -4499,6 +4511,7 @@ symtab_observer_executable_changed (void
initializing it from SYMTAB, LINENO and PC. */
static void
append_expanded_sal (struct symtabs_and_lines *sal,
+ struct symbol_space *sspace,
struct symtab *symtab,
int lineno, CORE_ADDR pc)
{
@@ -4506,6 +4519,7 @@ append_expanded_sal (struct symtabs_and_
sizeof (sal->sals[0])
* (sal->nelts + 1));
init_sal (sal->sals + sal->nelts);
+ sal->sals[sal->nelts].sspace = sspace;
sal->sals[sal->nelts].symtab = symtab;
sal->sals[sal->nelts].section = NULL;
sal->sals[sal->nelts].end = 0;
@@ -4525,14 +4539,16 @@ append_exact_match_to_sals (char *filena
struct linetable_entry **best_item,
struct symtab **best_symtab)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
struct symtab *symtab;
int exact = 0;
int j;
*best_item = 0;
*best_symtab = 0;
-
- ALL_SYMTABS (objfile, symtab)
+
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_SYMTABS (sspace, objfile, symtab)
{
if (strcmp (filename, symtab->filename) == 0)
{
@@ -4550,7 +4566,8 @@ append_exact_match_to_sals (char *filena
if (item->line == lineno)
{
exact = 1;
- append_expanded_sal (ret, symtab, lineno, item->pc);
+ append_expanded_sal (ret, objfile->sspace,
+ symtab, lineno, item->pc);
}
else if (!exact && item->line > lineno
&& (*best_item == NULL
@@ -4565,11 +4582,10 @@ append_exact_match_to_sals (char *filena
return exact;
}

-/* Compute a set of all sals in
- the entire program that correspond to same file
- and line as SAL and return those. If there
- are several sals that belong to the same block,
- only one sal for the block is included in results. */
+/* Compute a set of all sals in all symbol spaces that correspond to
+ same file and line as SAL and return those. If there are several
+ sals that belong to the same block, only one sal for the block is
+ included in results. */

struct symtabs_and_lines
expand_line_sal (struct symtab_and_line sal)
@@ -4583,10 +4599,12 @@ expand_line_sal (struct symtab_and_line
int deleted = 0;
struct block **blocks = NULL;
int *filter;
+ struct cleanup *old_chain;

ret.nelts = 0;
ret.sals = NULL;

+ /* Only expand sals that represent file.c:line. */
if (sal.symtab == NULL || sal.line == 0 || sal.pc != 0)
{
ret.sals = xmalloc (sizeof (struct symtab_and_line));
@@ -4596,11 +4614,14 @@ expand_line_sal (struct symtab_and_line
}
else
{
+ struct symbol_space *sspace;
struct linetable_entry *best_item = 0;
struct symtab *best_symtab = 0;
int exact = 0;
+ char *match_filename;

lineno = sal.line;
+ match_filename = sal.symtab->filename;

/* We need to find all symtabs for a file which name
is described by sal. We cannot just directly
@@ -4613,17 +4634,24 @@ expand_line_sal (struct symtab_and_line
the right name. Then, we iterate over symtabs, knowing
that all symtabs we're interested in are loaded. */

- ALL_PSYMTABS (objfile, psymtab)
+ old_chain = save_current_symbol_space ();
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_PSYMTABS (sspace, objfile, psymtab)
{
- if (strcmp (sal.symtab->filename,
- psymtab->filename) == 0)
- PSYMTAB_TO_SYMTAB (psymtab);
+ if (strcmp (match_filename, psymtab->filename) == 0)
+ {
+ set_current_symbol_space (sspace);
+
+ PSYMTAB_TO_SYMTAB (psymtab);
+
+ }
}
+ do_cleanups (old_chain);

/* Now search the symtab for exact matches and append them. If
none is found, append the best_item and all its exact
matches. */
- exact = append_exact_match_to_sals (sal.symtab->filename, lineno,
+ exact = append_exact_match_to_sals (match_filename, lineno,
&ret, &best_item, &best_symtab);
if (!exact && best_item)
append_exact_match_to_sals (best_symtab->filename, best_item->line,
@@ -4639,13 +4667,21 @@ expand_line_sal (struct symtab_and_line
blocks -- for each PC found above we see if there are other PCs
that are in the same block. If yes, the other PCs are filtered out. */

+ old_chain = save_current_symbol_space ();
filter = alloca (ret.nelts * sizeof (int));
blocks = alloca (ret.nelts * sizeof (struct block *));
for (i = 0; i < ret.nelts; ++i)
{
+ struct blockvector *bl;
+ struct block *b;
+
+ set_current_symbol_space (ret.sals[i].sspace);
+
filter[i] = 1;
- blocks[i] = block_for_pc (ret.sals[i].pc);
+ blocks[i] = block_for_pc_sect (ret.sals[i].pc, ret.sals[i].section);
+
}
+ do_cleanups (old_chain);

for (i = 0; i < ret.nelts; ++i)
if (blocks[i] != NULL)
Index: src/gdb/symtab.h
===================================================================
--- src.orig/gdb/symtab.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/symtab.h 2009-06-15 15:24:22.000000000 +0100
@@ -32,6 +32,7 @@ struct block;
struct blockvector;
struct axs_value;
struct agent_expr;
+struct symbol_space;

/* Some of the structures in this file are space critical.
The space-critical structures are:
@@ -813,6 +814,7 @@ struct symtab

#define BLOCKVECTOR(symtab) (symtab)->blockvector
#define LINETABLE(symtab) (symtab)->linetable
+#define SYMTAB_SSPACE(symtab) (symtab)->objfile->sspace
\f

/* Each source file that has not been fully read in is represented by
@@ -1160,6 +1162,9 @@ extern void msymbols_sort (struct objfil

struct symtab_and_line
{
+ /* The symbol space of this sal. */
+ struct symbol_space *sspace;
+
struct symtab *symtab;
struct obj_section *section;
/* Line number. Line numbers start at 1 and proceed through symtab->nlines.
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/target.c 2009-06-15 16:08:07.000000000 +0100
@@ -1933,7 +1933,7 @@ target_detach (char *args, int from_tty)
else
/* If we're in breakpoints-always-inserted mode, have to remove
them before detaching. */
- remove_breakpoints ();
+ remove_breakpoints_pid (PIDGET (inferior_ptid));

for (t = current_target.beneath; t != NULL; t = t->beneath)
{
@@ -2432,6 +2432,29 @@ target_get_osdata (const char *type)
return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
}

+/* Determine the current address space of thread PTID. */
+
+struct address_space *
+target_thread_address_space (ptid_t ptid)
+{
+ struct target_ops *t;
+ struct inferior *inf;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_thread_address_space != NULL)
+ return (*t->to_thread_address_space) (t, ptid);
+
+ /* Fall-back to the "main" address space of the inferior. */
+ inf = find_inferior_pid (ptid_get_pid (ptid));
+
+ if (inf == NULL || inf->aspace == NULL)
+ internal_error (__FILE__, __LINE__, "\
+Can't determine the current address space of thread %s\n",
+ target_pid_to_str (ptid));
+
+ return inf->aspace;
+}
+
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/target.h 2009-06-15 15:24:22.000000000 +0100
@@ -542,6 +542,10 @@ struct target_ops
simultaneously? */
int (*to_supports_multi_process) (void);

+ /* Determine current address space of thread PTID. */
+ struct address_space *(*to_thread_address_space) (struct target_ops *,
+ ptid_t);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -651,6 +655,10 @@ extern void target_store_registers (stru
#define target_prepare_to_store(regcache) \
(*current_target.to_prepare_to_store) (regcache)

+/* Determine current address space of thread PTID. */
+
+struct address_space *target_thread_address_space (ptid_t);
+
/* Returns true if this target can debug multiple processes
simultaneously. */

Index: src/gdb/testsuite/config/monitor.exp
===================================================================
--- src.orig/gdb/testsuite/config/monitor.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/config/monitor.exp 2009-06-15 15:24:22.000000000 +0100
@@ -123,7 +123,7 @@ proc gdb_target_monitor { exec_file } {
}

proc gdb_target_exec { } {
- gdb_test "target exec" "No executable file now." "" ".*Kill it.*y or n.*" "y"
+ gdb_test "target exec" "No executable files now." "" ".*Kill it.*y or n.*" "y"

}
#
Index: src/gdb/testsuite/gdb.base/checkpoint.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/checkpoint.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/checkpoint.exp 2009-06-15 15:24:22.000000000 +0100
@@ -46,6 +46,9 @@ gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
+set prev_timeout $timeout
+set timeout 600
+verbose "Timeout now 600 sec.\n"

global gdb_prompt

@@ -383,3 +386,7 @@ gdb_test "kill" "" "kill all one" \
#

remote_exec build "rm -f pi.txt"
+
+# Restore old timeout
+set timeout $prev_timeout
+verbose "Timeout now $timeout sec.\n"
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/top.c 2009-06-15 16:08:07.000000000 +0100
@@ -1195,20 +1195,6 @@ struct qt_args
int from_tty;
};

-/* Callback for iterate_over_threads. Finds any thread of inferior
- given by ARG (really an int*). */
-
-static int
-any_thread_of (struct thread_info *thread, void *arg)
-{
- int pid = * (int *)arg;
-
- if (PIDGET (thread->ptid) == pid)
- return 1;
-
- return 0;
-}
-
/* Callback for iterate_over_inferiors. Kills or detaches the given
inferior, depending on how we originally gained control of it. */

@@ -1218,7 +1204,7 @@ kill_or_detach (struct inferior *inf, vo
struct qt_args *qt = args;
struct thread_info *thread;

- thread = iterate_over_threads (any_thread_of, &inf->pid);
+ thread = any_thread_of_process (inf->pid);
if (thread)
{
switch_to_thread (thread->ptid);
Index: src/gdb/solib-svr4.c
===================================================================
--- src.orig/gdb/solib-svr4.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/solib-svr4.c 2009-06-15 15:24:22.000000000 +0100
@@ -273,11 +273,11 @@ IGNORE_FIRST_LINK_MAP_ENTRY (struct so_l
ptr_type) == 0;
}

-/* Per-inferior SVR4 specific data. */
+/* Per sspace SVR4 specific data. */

struct svr4_info
{
- int pid;
+ struct symbol_space *sspace;

CORE_ADDR debug_base; /* Base of dynamic linker structures */

@@ -292,6 +292,11 @@ struct svr4_info

/* Load map address for the main executable. */
CORE_ADDR main_lm_addr;
+
+ CORE_ADDR interp_text_sect_low;
+ CORE_ADDR interp_text_sect_high;
+ CORE_ADDR interp_plt_sect_low;
+ CORE_ADDR interp_plt_sect_high;
};

/* List of known processes using solib-svr4 shared libraries, storing
@@ -301,25 +306,23 @@ typedef struct svr4_info *svr4_info_p;
DEF_VEC_P(svr4_info_p);
VEC(svr4_info_p) *svr4_info = NULL;

-/* Get svr4 data for inferior PID (target id). If none is found yet,
- add it now. This function always returns a valid object. */
+/* Get the current svr4 data. If none is found yet, add it now. This
+ function always returns a valid object. */

struct svr4_info *
-get_svr4_info (int pid)
+get_svr4_info (void)
{
int ix;
struct svr4_info *it;

- gdb_assert (pid != 0);
-
for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
{
- if (it->pid == pid)
+ if (it->sspace == current_symbol_space)
return it;
}

it = XZALLOC (struct svr4_info);
- it->pid = pid;
+ it->sspace = current_symbol_space;

VEC_safe_push (svr4_info_p, svr4_info, it);

@@ -330,14 +333,14 @@ get_svr4_info (int pid)
id). */

static void
-remove_svr4_info (int pid)
+remove_svr4_info (void)
{
int ix;
struct svr4_info *it;

for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
{
- if (it->pid == pid)
+ if (it->sspace == current_symbol_space)
{
VEC_unordered_remove (svr4_info_p, svr4_info, ix);
return;
@@ -345,18 +348,6 @@ remove_svr4_info (int pid)
}
}

-/* This is an "inferior_exit" observer. Inferior PID (target id) is
- being removed from the inferior list, because it exited, was
- killed, detached, or we just dropped the connection to the debug
- interface --- discard any solib-svr4 related bookkeeping for this
- inferior. */
-
-static void
-solib_svr4_inferior_exit (int pid)
-{
- remove_svr4_info (pid);
-}
-
/* Local function prototypes */

static int match_main (char *);
@@ -918,7 +909,7 @@ open_symbol_file_object (void *from_ttyp
int l_name_size = TYPE_LENGTH (ptr_type);
gdb_byte *l_name_buf = xmalloc (l_name_size);
struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
- struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
+ struct svr4_info *info = get_svr4_info ();

if (symfile_objfile)
if (!query (_("Attempt to reload symbols from process? ")))
@@ -969,8 +960,7 @@ open_symbol_file_object (void *from_ttyp
static struct so_list *
svr4_default_sos (void)
{
- struct inferior *inf = current_inferior ();
- struct svr4_info *info = get_svr4_info (inf->pid);
+ struct svr4_info *info = get_svr4_info ();

struct so_list *head = NULL;
struct so_list **link_ptr = &head;
@@ -992,6 +982,8 @@ svr4_default_sos (void)
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (new->so_original_name, new->so_name);

+ new->sspace = current_symbol_space;
+
*link_ptr = new;
link_ptr = &new->next;
}
@@ -1025,14 +1017,9 @@ svr4_current_sos (void)
struct so_list *head = 0;
struct so_list **link_ptr = &head;
CORE_ADDR ldsomap = 0;
- struct inferior *inf;
struct svr4_info *info;

- if (ptid_equal (inferior_ptid, null_ptid))
- return NULL;
-
- inf = current_inferior ();
- info = get_svr4_info (inf->pid);
+ info = get_svr4_info ();

/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
@@ -1059,6 +1046,7 @@ svr4_current_sos (void)
new->lm_info->l_addr = (CORE_ADDR)-1;
new->lm_info->lm_addr = lm;
new->lm_info->lm = xzalloc (lmo->link_map_size);
+ new->sspace = current_symbol_space;
make_cleanup (xfree, new->lm_info->lm);

read_memory (lm, new->lm_info->lm, lmo->link_map_size);
@@ -1129,7 +1117,7 @@ CORE_ADDR
svr4_fetch_objfile_link_map (struct objfile *objfile)
{
struct so_list *so;
- struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
+ struct svr4_info *info = get_svr4_info ();

/* Cause svr4_current_sos() to be run if it hasn't been already. */
if (info->main_lm_addr == 0)
@@ -1169,16 +1157,16 @@ match_main (char *soname)

/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
-static CORE_ADDR interp_text_sect_low;
-static CORE_ADDR interp_text_sect_high;
-static CORE_ADDR interp_plt_sect_low;
-static CORE_ADDR interp_plt_sect_high;

int
svr4_in_dynsym_resolve_code (CORE_ADDR pc)
{
- return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
- || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
+ struct svr4_info *info = get_svr4_info ();
+
+ return ((pc >= info->interp_text_sect_low
+ && pc < info->interp_text_sect_high)
+ || (pc >= info->interp_plt_sect_low
+ && pc < info->interp_plt_sect_high)
|| in_plt_section (pc, NULL));
}

@@ -1252,14 +1240,13 @@ enable_break (struct svr4_info *info)
asection *interp_sect;
gdb_byte *interp_name;
CORE_ADDR sym_addr;
- struct inferior *inf = current_inferior ();

/* First, remove all the solib event breakpoints. Their addresses
may have changed since the last time we ran the program. */
remove_solib_event_breakpoints ();

- interp_text_sect_low = interp_text_sect_high = 0;
- interp_plt_sect_low = interp_plt_sect_high = 0;
+ info->interp_text_sect_low = info->interp_text_sect_high = 0;
+ info->interp_plt_sect_low = info->interp_plt_sect_high = 0;

/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
@@ -1295,18 +1282,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_text_sect_high =
- interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_text_sect_high =
+ info->interp_text_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
- interp_plt_sect_low =
+ info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_plt_sect_high =
- interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}

create_solib_event_breakpoint (sym_addr);
@@ -1398,18 +1387,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_text_sect_high =
- interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_text_sect_high =
+ info->interp_text_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
- interp_plt_sect_low =
+ info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_plt_sect_high =
- interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}

/* Now try to set a breakpoint in the dynamic linker. */
@@ -1669,7 +1660,7 @@ svr4_solib_create_inferior_hook (void)
struct thread_info *tp;
struct svr4_info *info;

- info = get_svr4_info (PIDGET (inferior_ptid));
+ info = get_svr4_info ();

/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -1709,7 +1700,7 @@ svr4_solib_create_inferior_hook (void)
static void
svr4_clear_solib (void)
{
- remove_svr4_info (PIDGET (inferior_ptid));
+ remove_svr4_info ();
}

static void
@@ -1919,6 +1910,4 @@ _initialize_svr4_solib (void)
svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
-
- observer_attach_inferior_exit (solib_svr4_inferior_exit);
}
Index: src/gdb/solist.h
===================================================================
--- src.orig/gdb/solist.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/solist.h 2009-06-15 15:24:22.000000000 +0100
@@ -52,6 +52,9 @@ struct so_list
/* shared object file name, expanded to something GDB can open */
char so_name[SO_NAME_MAX_PATH_SIZE];

+ /* Symbol space this shared library belongs to. */
+ struct symbol_space *sspace;
+
/* The following fields of the structure are built from
information gathered from the shared object file itself, and
are set when we actually add it to our symbol tables.
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/printcmd.c 2009-06-15 15:24:22.000000000 +0100
@@ -134,16 +134,25 @@ struct display
{
/* Chain link to next auto-display item. */
struct display *next;
+
/* The expression as the user typed it. */
char *exp_string;
+
/* Expression to be evaluated and displayed. */
struct expression *exp;
+
/* Item number of this auto-display item. */
int number;
+
/* Display format specified. */
struct format_data format;
+
+ /* Symbol space associated with `block'. */
+ struct symbol_space *sspace;
+
/* Innermost block required by this expression when evaluated */
struct block *block;
+
/* Status of this display (enabled or disabled) */
int enabled_p;
};
@@ -1440,6 +1449,7 @@ display_command (char *exp, int from_tty
new->exp_string = xstrdup (exp);
new->exp = expr;
new->block = innermost_block;
+ new->sspace = current_symbol_space;
new->next = display_chain;
new->number = ++display_number;
new->format = fmt;
@@ -1576,7 +1586,12 @@ do_one_display (struct display *d)
}

if (d->block)
- within_current_scope = contained_in (get_selected_block (0), d->block);
+ {
+ if (d->sspace == current_symbol_space)
+ within_current_scope = contained_in (get_selected_block (0), d->block);
+ else
+ within_current_scope = 0;
+ }
else
within_current_scope = 1;
if (!within_current_scope)
@@ -1801,6 +1816,7 @@ display_uses_solib_p (const struct displ
const union exp_element *const elts = exp->elts;

if (d->block != NULL
+ && d->sspace == solib->sspace
&& solib_contains_address_p (solib, d->block->startaddr))
return 1;

@@ -1819,9 +1835,15 @@ display_uses_solib_p (const struct displ
const struct symbol *const symbol = elts[i + 2].symbol;
const struct obj_section *const section =
SYMBOL_OBJ_SECTION (symbol);
+#if 0
+ /* FIXME: this info isn't there yet. */
+ const struct symbol_space *sspace = elts[i + 3].symbol;
+#endif

if (block != NULL
- && solib_contains_address_p (solib, block->startaddr))
+ /* FIXME: && sspace == solib->sspace */
+ && solib_contains_address_p (solib,
+ block->startaddr))
return 1;

if (section && section->objfile == solib->objfile)
Index: src/gdb/solib.h
===================================================================
--- src.orig/gdb/solib.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/solib.h 2009-06-15 15:24:22.000000000 +0100
@@ -25,6 +25,7 @@
struct so_list;
struct target_ops;
struct target_so_ops;
+struct symbol_space;

/* Called when we free all symtabs, to free the shared library information
as well. */
@@ -45,7 +46,7 @@ extern void solib_create_inferior_hook (

/* If ADDR lies in a shared library, return its name. */

-extern char *solib_name_from_address (CORE_ADDR);
+extern char *solib_name_from_address (struct symbol_space *, CORE_ADDR);

/* Return 1 if ADDR lies within SOLIB. */

Index: src/gdb/stack.c
===================================================================
--- src.orig/gdb/stack.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/stack.c 2009-06-15 15:24:22.000000000 +0100
@@ -605,7 +605,8 @@ print_frame_info (struct frame_info *fra
}

if (print_what != LOCATION)
- set_default_breakpoint (1, get_frame_pc (frame), sal.symtab, sal.line);
+ set_default_breakpoint (1, sal.sspace,
+ get_frame_pc (frame), sal.symtab, sal.line);

annotate_frame_end ();

@@ -776,7 +777,8 @@ print_frame (struct frame_info *frame, i
#ifdef PC_SOLIB
char *lib = PC_SOLIB (get_frame_pc (frame));
#else
- char *lib = solib_name_from_address (get_frame_pc (frame));
+ char *lib = solib_name_from_address (get_frame_symbol_space (frame),
+ get_frame_pc (frame));
#endif
if (lib)
{
Index: src/gdb/gdbthread.h
===================================================================
--- src.orig/gdb/gdbthread.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/gdbthread.h 2009-06-15 15:24:22.000000000 +0100
@@ -241,6 +241,8 @@ struct thread_info *first_thread_of_proc
/* Returns any thread of process PID. */
extern struct thread_info *any_thread_of_process (int pid);

+extern struct thread_info *any_live_thread_of_process (int pid);
+
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);

Index: src/gdb/linux-fork.c
===================================================================
--- src.orig/gdb/linux-fork.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/linux-fork.c 2009-06-15 15:24:22.000000000 +0100
@@ -27,6 +27,7 @@
#include "gdb_string.h"
#include "linux-fork.h"
#include "linux-nat.h"
+#include "gdbthread.h"

#include <sys/ptrace.h>
#include "gdb_wait.h"
@@ -40,9 +41,6 @@ static int highest_fork_num;
/* Prevent warning from -Wmissing-prototypes. */
extern void _initialize_linux_fork (void);

-int detach_fork = 1; /* Default behavior is to detach
- newly forked processes (legacy). */
-
/* Fork list data structure: */
struct fork_info
{
@@ -646,14 +644,6 @@ _initialize_linux_fork (void)
{
init_fork_list ();

- /* Set/show detach-on-fork: user-settable mode. */
-
- add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
-Set whether gdb will detach the child of a fork."), _("\
-Show whether gdb will detach the child of a fork."), _("\
-Tells gdb whether to detach the child of a fork."),
- NULL, NULL, &setlist, &showlist);
-
/* Set/show restart-auto-finish: user-settable count. Causes the
first "restart" of a fork to do some number of "finish" commands
before returning to user.
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/thread.c 2009-06-15 15:24:22.000000000 +0100
@@ -440,6 +440,24 @@ any_thread_of_process (int pid)
return NULL;
}

+struct thread_info *
+any_live_thread_of_process (int pid)
+{
+ struct thread_info *tp;
+ struct thread_info *tp_running = NULL;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (ptid_get_pid (tp->ptid) == pid)
+ {
+ if (tp->state_ == THREAD_STOPPED)
+ return tp;
+ else if (tp->state_ == THREAD_RUNNING)
+ tp_running = tp;
+ }
+
+ return tp_running;
+}
+
/* Print a list of thread ids currently known, and the total number of
threads. To be used from within catch_errors. */
static int
@@ -849,6 +867,10 @@ switch_to_thread (ptid_t ptid)
return;

inferior_ptid = ptid;
+
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ set_current_symbol_space (current_inferior ()->sspace);
+
reinit_frame_cache ();
registers_changed ();

Index: src/gdb/arm-tdep.c
===================================================================
--- src.orig/gdb/arm-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/arm-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -2170,7 +2170,8 @@ arm_software_single_step (struct frame_i
CPSR heuristics are used. */

CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ next_pc);

return 1;
}
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/infrun.c 2009-06-15 16:00:19.000000000 +0100
@@ -107,6 +107,9 @@ int sync_execution = 0;

static ptid_t previous_inferior_ptid;

+/* Default behavior is to detach newly forked processes (legacy). */
+int detach_fork = 1;
+
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
@@ -459,6 +462,197 @@ follow_inferior_reset_breakpoints (void)
insert_breakpoints ();
}

+static int
+proceed_after_vfork_done (struct thread_info *thread,
+ void *arg)
+{
+ int pid = * (int *) arg;
+
+ if (ptid_get_pid (thread->ptid) == pid
+ && is_running (thread->ptid)
+ && !is_executing (thread->ptid)
+ && !thread->stop_requested
+ && thread->stop_signal == TARGET_SIGNAL_0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resuming vfork parent thread %s\n",
+ target_pid_to_str (thread->ptid));
+
+ switch_to_thread (thread->ptid);
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+
+ return 0;
+}
+
+/* Called whenever we notice an exec or exit event, to handle
+ detaching or resuming a vfork parent. */
+
+static void
+handle_vfork_child_exec_or_exit (int exec)
+{
+ struct inferior *inf = current_inferior ();
+
+ if (inf->vfork_parent)
+ {
+ int resume_parent = -1;
+
+ /* This exec or exit marks the end of the shared memory region
+ between the parent and the child. If the user wanted to
+ detach from the parent, now is the time. */
+
+ if (inf->vfork_parent->pending_detach)
+ {
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+ struct symbol_space *sspace;
+ struct address_space *aspace;
+
+ /* follow-fork child, detach-on-fork on */
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ /* We're letting loose of the parent. */
+ tp = any_live_thread_of_process (inf->vfork_parent->pid);
+ switch_to_thread (tp->ptid);
+
+ /* We're about to detach from the parent, which implicitly
+ removes breakpoints from its address space. There's a
+ catch here: we want to reuse the spaces for the child,
+ but, parent/child are still sharing the sspace at this
+ point, although the exec in reality makes the kernel give
+ the child a fresh set of new pages. The problem here is
+ that the breakpoints module being unaware of this, would
+ likely chose the child process to write to the parent
+ address space. Swapping the child temporarily away from
+ the spaces has the desired effect. Yes, this is "sort
+ of" a hack. */
+
+ sspace = inf->sspace;
+ aspace = inf->aspace;
+ inf->aspace = NULL;
+ inf->sspace = NULL;
+
+ if (debug_infrun || info_verbose)
+ {
+ target_terminal_ours ();
+
+ if (exec)
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exec.\n",
+ inf->vfork_parent->pid);
+ else
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exit.\n",
+ inf->vfork_parent->pid);
+ }
+
+ target_detach (NULL, 0);
+
+ /* Put it back. */
+ inf->sspace = sspace;
+ inf->aspace = aspace;
+
+ do_cleanups (old_chain);
+ }
+ else if (exec)
+ {
+ /* We're staying attached to the parent, so, really give the
+ child a new address space. */
+ inf->sspace = add_symbol_space (maybe_new_address_space ());
+ inf->aspace = inf->sspace->aspace;
+ inf->sspace->removable = 1;
+ set_current_symbol_space (inf->sspace);
+
+ resume_parent = inf->vfork_parent->pid;
+
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+ else
+ {
+ struct cleanup *old_chain;
+ struct symbol_space *sspace;
+
+ /* If this is a vfork child exiting, then the sspace and
+ aspaces where shared with the parent. Since we're
+ reporting the process exit, we'll be mourning all that is
+ found in the address space, and switching to null_ptid,
+ preparing to start a new inferior. But, since we don't
+ want to clobber the parent's address/symbol spaces, we go
+ ahead and create a new one for this exiting inferior.
+ The alternative, is to make normal_stop switch to the
+ parent process automatically, without messing up with the
+ parent's spaces. */
+
+ /* Switch to null_ptid, so that clone_symbol_space doesn't want
+ to read the selected frame of a dead process. */
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = null_ptid;
+
+ /* This inferior is dead, so avoid giving the breakpoints
+ module the option to write through to it (cloning a
+ symbol space resets breakpoints). */
+ inf->aspace = NULL;
+ inf->sspace = NULL;
+ sspace = add_symbol_space (maybe_new_address_space ());
+ set_current_symbol_space (sspace);
+ sspace->removable = 1;
+ clone_symbol_space (sspace, inf->vfork_parent->sspace);
+ inf->sspace = sspace;
+ inf->aspace = sspace->aspace;
+
+ /* Put back inferior_ptid. We'll continue mourning this
+ inferior. */
+ do_cleanups (old_chain);
+
+ resume_parent = inf->vfork_parent->pid;
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+
+ inf->vfork_parent = NULL;
+
+ gdb_assert (current_symbol_space == inf->sspace);
+
+ if (non_stop && resume_parent != -1)
+ {
+ /* If the user wanted the parent to be running, let it go
+ free now. */
+ struct cleanup *old_chain = make_cleanup_restore_current_thread ();
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent process %d\n",
+ resume_parent);
+
+ iterate_over_threads (proceed_after_vfork_done, &resume_parent);
+
+ do_cleanups (old_chain);
+ }
+ }
+}
+
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char follow_exec_mode_replace[] = "replace";
+static const char follow_exec_mode_keep[] = "keep";
+static const char *follow_exec_mode_names[] =
+{
+ follow_exec_mode_replace,
+ follow_exec_mode_keep,
+ NULL,
+};
+
+static const char *follow_exec_mode_string = follow_exec_mode_replace;
+static void
+show_follow_exec_mode_string (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
+}
+
/* EXECD_PATHNAME is assumed to be non-NULL. */

static void
@@ -466,6 +660,7 @@ follow_exec (ptid_t pid, char *execd_pat
{
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
+ struct inferior *inf = current_inferior ();

/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@@ -487,6 +682,12 @@ follow_exec (ptid_t pid, char *execd_pat
that may write the bp's "shadow contents" (the instruction
value that was overwritten witha TRAP instruction). Since
we now have a new a.out, those shadow contents aren't valid. */
+
+ /* Do whatever is necessary to the parent branch of the vfork. */
+ handle_vfork_child_exec_or_exit (1);
+
+ mark_breakpoints_out ();
+
update_breakpoints_after_exec ();

/* If there was one, it's gone now. We cannot truly step-to-next
@@ -504,7 +705,9 @@ follow_exec (ptid_t pid, char *execd_pat
th->stop_requested = 0;

/* What is this a.out's name? */
- printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
+ printf_unfiltered (_("%s is executing new program: %s\n"),
+ target_pid_to_str (inferior_ptid),
+ execd_pathname);

/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
@@ -523,9 +726,6 @@ follow_exec (ptid_t pid, char *execd_pat
execd_pathname = name;
}

- /* That a.out is now the one to use. */
- exec_file_attach (execd_pathname, 0);
-
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
dld will have had a chance to initialize the child. */
@@ -534,6 +734,25 @@ follow_exec (ptid_t pid, char *execd_pat
previous incarnation of this process. */
no_shared_libraries (NULL, 0);

+ if (follow_exec_mode_string == follow_exec_mode_keep)
+ {
+ struct symbol_space *sspace;
+
+ /* The user wants to keep the old symbol space around. Create a
+ new fresh one, and switch to it. */
+
+ sspace = add_symbol_space (maybe_new_address_space ());
+ sspace->removable = 1;
+ set_current_symbol_space (sspace);
+ inf->sspace = sspace;
+ inf->aspace = sspace->aspace;
+ }
+
+ gdb_assert (current_symbol_space == inf->sspace);
+
+ /* That a.out is now the one to use. */
+ exec_file_attach (execd_pathname, 0);
+
/* Load the main file's symbols. */
symbol_file_add_main (execd_pathname, 0);

@@ -967,8 +1186,10 @@ displaced_step_fixup (ptid_t event_ptid,
while (displaced_step_request_queue)
{
struct displaced_step_request *head;
+ struct frame_info *frame;
ptid_t ptid;
CORE_ADDR actual_pc;
+ struct regcache *regcache;

head = displaced_step_request_queue;
ptid = head->ptid;
@@ -977,9 +1198,10 @@ displaced_step_fixup (ptid_t event_ptid,

context_switch (ptid);

- actual_pc = regcache_read_pc (get_thread_regcache (ptid));
+ regcache = get_thread_regcache (ptid);
+ actual_pc = regcache_read_pc (regcache);

- if (breakpoint_here_p (actual_pc))
+ if (breakpoint_here_p (get_regcache_aspace (regcache), actual_pc))
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
@@ -1137,6 +1359,7 @@ resume (int step, enum target_signal sig
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);

QUIT;

@@ -1162,7 +1385,7 @@ resume (int step, enum target_signal sig
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
- if (breakpoint_here_p (pc) == permanent_breakpoint_here)
+ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
@@ -1275,7 +1498,7 @@ a command like `return' or `jump' to con
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
- if (step && breakpoint_inserted_here_p (pc))
+ if (step && breakpoint_inserted_here_p (aspace, pc))
step = 0;
}

@@ -1347,23 +1570,26 @@ clear_proceed_status_callback (struct th
void
clear_proceed_status (void)
{
+ if (!non_stop)
+ {
+ /* In all-stop mode, delete the per-thread status of all
+ threads, even if inferior_ptid is null_ptid, there may be
+ threads on the list. E.g., we may be launching a new
+ process, while selecting the executable. */
+ iterate_over_threads (clear_proceed_status_callback, NULL);
+ }
+
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inferior;

if (non_stop)
{
- /* If in non-stop mode, only delete the per-thread status
- of the current thread. */
+ /* If in non-stop mode, only delete the per-thread status of
+ the current thread. */
clear_proceed_status_thread (inferior_thread ());
}
- else
- {
- /* In all-stop mode, delete the per-thread status of
- *all* threads. */
- iterate_over_threads (clear_proceed_status_callback, NULL);
- }
-
+
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
}
@@ -1425,7 +1651,8 @@ prepare_to_proceed (int step)
{
struct regcache *regcache = get_thread_regcache (wait_ptid);

- if (breakpoint_here_p (regcache_read_pc (regcache)))
+ if (breakpoint_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache)))
{
/* If stepping, remember current thread to switch back to. */
if (step)
@@ -1463,6 +1690,7 @@ proceed (CORE_ADDR addr, enum target_sig
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
+ struct address_space *aspace;
int oneproc = 0;

/* If we're stopped at a fork/vfork, follow the branch set by the
@@ -1477,6 +1705,7 @@ proceed (CORE_ADDR addr, enum target_sig

regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
+ aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);

if (step > 0)
@@ -1486,7 +1715,7 @@ proceed (CORE_ADDR addr, enum target_sig

if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc && breakpoint_here_p (pc)
+ if (pc == stop_pc && breakpoint_here_p (aspace, pc)
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
step one instruction before inserting breakpoints so that
@@ -2207,6 +2436,7 @@ adjust_pc_after_break (struct execution_
{
struct regcache *regcache;
struct gdbarch *gdbarch;
+ struct address_space *aspace;
CORE_ADDR breakpoint_pc;

/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
@@ -2272,6 +2502,8 @@ adjust_pc_after_break (struct execution_
if (gdbarch_decr_pc_after_break (gdbarch) == 0)
return;

+ aspace = get_regcache_aspace (regcache);
+
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
@@ -2285,8 +2517,8 @@ adjust_pc_after_break (struct execution_
already queued and arrive later. To suppress those spurious
SIGTRAPs, we keep a list of such breakpoint locations for a bit,
and retire them after a number of stop events are reported. */
- if (software_breakpoint_inserted_here_p (breakpoint_pc)
- || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
+ if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
@@ -2520,7 +2752,11 @@ handle_inferior_event (struct execution_
case TARGET_WAITKIND_EXITED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
+
inferior_ptid = ecs->ptid;
+ set_current_symbol_space (current_inferior ()->sspace);
+ handle_vfork_child_exec_or_exit (0);
+
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);

@@ -2539,6 +2775,8 @@ handle_inferior_event (struct execution_
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
inferior_ptid = ecs->ptid;
+ set_current_symbol_space (current_inferior ()->sspace);
+ handle_vfork_child_exec_or_exit (0);
stop_print_frame = 0;
target_terminal_ours (); /* Must do this before mourn anyway */

@@ -2595,19 +2833,45 @@ handle_inferior_event (struct execution_

stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));

- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);

ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);

/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
+ ptid_t parent;
+ ptid_t child;
int should_resume;
+ int follow_child = (follow_fork_mode_string == follow_fork_mode_child);

ecs->event_thread->stop_signal = TARGET_SIGNAL_0;

should_resume = follow_fork ();

+ parent = ecs->ptid;
+ child = ecs->ws.value.related_pid;
+
+ /* In non-stop mode, also resume the other branch. */
+ if (non_stop && !detach_fork)
+ {
+ if (follow_child)
+ switch_to_thread (parent);
+ else
+ switch_to_thread (child);
+
+ ecs->event_thread = inferior_thread ();
+ ecs->ptid = inferior_ptid;
+ keep_going (ecs);
+ }
+
+ if (follow_child)
+ switch_to_thread (child);
+ else
+ switch_to_thread (parent);
+
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;

@@ -2637,7 +2901,9 @@ handle_inferior_event (struct execution_
stop. */
follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);

- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);

/* Note that this may be referenced from inside
@@ -2836,14 +3102,15 @@ targets should add new threads to the th
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
+ struct address_space *aspace = get_regcache_aspace (get_current_regcache ());

/* Check if a regular breakpoint has been hit before checking
for a potential single step breakpoint. Otherwise, GDB will
not see this breakpoint hit when stepping onto breakpoints. */
- if (regular_breakpoint_inserted_here_p (stop_pc))
+ if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
{
ecs->random_signal = 0;
- if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
thread_hop_needed = 1;
}
else if (singlestep_breakpoints_inserted_p)
@@ -3121,7 +3388,8 @@ targets should add new threads to the th
non-standard signals can't be explained by the breakpoint. */
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
|| (! ecs->event_thread->trap_expected
- && breakpoint_inserted_here_p (stop_pc)
+ && breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()),
+ stop_pc)
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
@@ -3178,8 +3446,10 @@ targets should add new threads to the th
}

/* See if there is a breakpoint at the current PC. */
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
+
/* Following in case break condition called a
function. */
stop_print_frame = 1;
@@ -3671,6 +3941,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());

insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
}
@@ -3765,6 +4036,7 @@ infrun: not switching back to stepped th
/* Normal (staticly linked) function call return. */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());
insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
}
else
@@ -3791,6 +4063,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());

insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
keep_going (ecs);
@@ -3836,6 +4109,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());
insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
}
else
@@ -3869,6 +4143,7 @@ infrun: not switching back to stepped th
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());

/* Do not specify what the fp should be when we stop since
on some machines the prologue is where the new fp value
@@ -4072,6 +4347,7 @@ handle_step_into_function (struct execut
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());

/* Do not specify what the fp should be when we stop since on
some machines the prologue is where the new fp value is
@@ -4160,6 +4436,7 @@ insert_step_resume_breakpoint_at_frame (
sr_sal.pc = gdbarch_addr_bits_remove
(current_gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = get_frame_symbol_space (return_frame);

insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id (return_frame));
}
@@ -4193,6 +4470,7 @@ insert_step_resume_breakpoint_at_caller
sr_sal.pc = gdbarch_addr_bits_remove
(current_gdbarch, frame_pc_unwind (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = frame_unwind_symbol_space (next_frame);

insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame));
}
@@ -5763,6 +6041,25 @@ By default, the debugger will follow the
show_follow_fork_mode_string,
&setlist, &showlist);

+ add_setshow_enum_cmd ("follow-exec-mode", class_run,
+ follow_exec_mode_names,
+ &follow_exec_mode_string, _("\
+Set debugger response to a program call of exec."), _("\
+Show debugger response to a program call of exec."), _("\
+An exec call replaces the process'es program image. follow-exec-mode can be:\n\
+\n\
+ keep - The previous symbol space is kept so that it can\n\
+be restarted afterwards. The process is assigned a new symbol space.\n\
+\n\
+ replace - the process'es previous symbol space is reused. The new\n\
+executable replaces the previous executable in the symbol space.\n\
+\n\
+By default, the debugger will reuse the symbol space, replacing its main\n\
+executable."),
+ NULL,
+ show_follow_exec_mode_string,
+ &setlist, &showlist);
+
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
@@ -5821,6 +6118,14 @@ Options are 'forward' or 'reverse'."),
set_exec_direction_func, show_exec_direction_func,
&setlist, &showlist);

+ /* Set/show detach-on-fork: user-settable mode. */
+
+ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
+Set whether gdb will detach the child of a fork."), _("\
+Show whether gdb will detach the child of a fork."), _("\
+Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);
Index: src/gdb/regcache.c
===================================================================
--- src.orig/gdb/regcache.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/regcache.c 2009-06-15 15:24:22.000000000 +0100
@@ -185,6 +185,11 @@ register_size (struct gdbarch *gdbarch,
struct regcache
{
struct regcache_descr *descr;
+
+ /* The address space of this register cache (for registers where it
+ makes sense, like PC or SP). */
+ struct address_space *aspace;
+
/* The register buffers. A read-only register cache can hold the
full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) while a read/write
register cache can only hold [0 .. gdbarch_num_regs). */
@@ -219,6 +224,7 @@ regcache_xmalloc (struct gdbarch *gdbarc
= XCALLOC (descr->sizeof_raw_registers, gdb_byte);
regcache->register_valid_p
= XCALLOC (descr->sizeof_raw_register_valid_p, gdb_byte);
+ regcache->aspace = NULL;
regcache->readonly_p = 1;
regcache->ptid = minus_one_ptid;
return regcache;
@@ -254,6 +260,12 @@ get_regcache_arch (const struct regcache
return regcache->descr->gdbarch;
}

+struct address_space *
+get_regcache_aspace (const struct regcache *regcache)
+{
+ return regcache->aspace;
+}
+
/* Return a pointer to register REGNUM's buffer cache. */

static gdb_byte *
@@ -340,10 +352,14 @@ regcache_cpy (struct regcache *dst, stru
{
int i;
gdb_byte *buf;
+
gdb_assert (src != NULL && dst != NULL);
gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
gdb_assert (src != dst);
gdb_assert (src->readonly_p || dst->readonly_p);
+
+ /* FIXME: move this to regcache_xmalloc? */
+ dst->aspace = src->aspace;
if (!src->readonly_p)
regcache_save (dst, do_cooked_read, src);
else if (!dst->readonly_p)
@@ -362,6 +378,8 @@ regcache_cpy_no_passthrough (struct regc
move of data into the current regcache. Doing this would be
silly - it would mean that valid_p would be completely invalid. */
gdb_assert (dst->readonly_p);
+
+ dst->aspace = src->aspace;
memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
memcpy (dst->register_valid_p, src->register_valid_p,
dst->descr->sizeof_raw_register_valid_p);
@@ -435,6 +453,8 @@ struct regcache *get_thread_regcache (pt
current_regcache = regcache_xmalloc (thread_gdbarch);
current_regcache->readonly_p = 0;
current_regcache->ptid = ptid;
+ current_regcache->aspace = target_thread_address_space (ptid);
+ gdb_assert (current_regcache->aspace != NULL);

return current_regcache;
}
Index: src/gdb/regcache.h
===================================================================
--- src.orig/gdb/regcache.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/regcache.h 2009-06-15 15:24:22.000000000 +0100
@@ -23,6 +23,7 @@

struct regcache;
struct gdbarch;
+struct address_space;

extern struct regcache *get_current_regcache (void);
extern struct regcache *get_thread_regcache (ptid_t ptid);
@@ -35,6 +36,10 @@ struct regcache *regcache_xmalloc (struc

extern struct gdbarch *get_regcache_arch (const struct regcache *regcache);

+/* Return REGCACHE's address space. */
+
+extern struct address_space *get_regcache_aspace (const struct regcache *regcache);
+
/* Transfer a raw register [0..NUM_REGS) between core-gdb and the
regcache. */

Index: src/gdb/tui/tui-disasm.c
===================================================================
--- src.orig/gdb/tui/tui-disasm.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/tui/tui-disasm.c 2009-06-15 15:24:22.000000000 +0100
@@ -36,6 +36,7 @@
#include "tui/tui-stack.h"
#include "tui/tui-file.h"
#include "tui/tui-disasm.h"
+#include "symspace.h"

#include "gdb_curses.h"

@@ -257,7 +258,8 @@ tui_set_disassem_content (CORE_ADDR pc)

/* See whether there is a breakpoint installed. */
src->has_break = (!src->is_exec_point
- && breakpoint_here_p (pc) != no_breakpoint_here);
+ && breakpoint_here_p (current_symbol_space->aspace, pc)
+ != no_breakpoint_here);

xfree (asm_lines[i].addr_string);
xfree (asm_lines[i].insn);
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/infcall.c 2009-06-15 15:24:22.000000000 +0100
@@ -707,6 +707,7 @@ call_function_by_hand (struct value *fun
struct breakpoint *bpt;
struct symtab_and_line sal;
init_sal (&sal); /* initialize to zeroes */
+ sal.sspace = current_symbol_space;
sal.pc = bp_addr;
sal.section = find_pc_overlay (sal.pc);
/* Sanity. The exact same SP value is returned by
Index: src/gdb/testsuite/gdb.base/maint.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/maint.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/maint.exp 2009-06-15 15:24:22.000000000 +0100
@@ -480,9 +480,9 @@ set bp_location6 [gdb_get_line_number "s

send_gdb "maint info breakpoints\n"
gdb_expect {
- -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
+ -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6 sspace 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
{ pass "maint info breakpoints" }
- -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
+ -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6 sspace 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
{ pass "maint info breakpoints (with shlib events)" }
-re ".*$gdb_prompt $" { fail "maint info breakpoints" }
timeout { fail "(timeout) maint info breakpoints" }
Index: src/gdb/arch-utils.c
===================================================================
--- src.orig/gdb/arch-utils.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/arch-utils.c 2009-06-15 15:24:22.000000000 +0100
@@ -720,6 +720,14 @@ gdbarch_info_fill (struct gdbarch_info *
gdb_assert (info->bfd_arch_info != NULL);
}

+int
+default_has_shared_address_space (struct gdbarch *gdbarch)
+{
+ /* Simply say no. Most unix-like targets will export an address
+ space per inferior. */
+ return 0;
+}
+
/* */

extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
Index: src/gdb/arch-utils.h
===================================================================
--- src.orig/gdb/arch-utils.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/arch-utils.h 2009-06-15 15:24:22.000000000 +0100
@@ -139,4 +139,6 @@ extern void gdbarch_info_fill (struct gd

extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);

+extern int default_has_shared_address_space (struct gdbarch *);
+
#endif
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/gdbarch.c 2009-06-15 15:24:22.000000000 +0100
@@ -246,6 +246,7 @@ struct gdbarch
gdbarch_record_special_symbol_ftype *record_special_symbol;
int has_global_solist;
int has_global_breakpoints;
+ gdbarch_has_shared_address_space_ftype *has_shared_address_space;
};

@@ -383,6 +384,7 @@ struct gdbarch startup_gdbarch =
0, /* record_special_symbol */
0, /* has_global_solist */
0, /* has_global_breakpoints */
+ default_has_shared_address_space, /* has_shared_address_space */
/* startup_gdbarch() */
};

@@ -467,6 +469,7 @@ gdbarch_alloc (const struct gdbarch_info
gdbarch->displaced_step_location = NULL;
gdbarch->target_signal_from_host = default_target_signal_from_host;
gdbarch->target_signal_to_host = default_target_signal_to_host;
+ gdbarch->has_shared_address_space = default_has_shared_address_space;
/* gdbarch_alloc() */

return gdbarch;
@@ -641,6 +644,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of record_special_symbol, has predicate */
/* Skip verify of has_global_solist, invalid_p == 0 */
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
+ /* Skip verify of has_shared_address_space, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
@@ -871,6 +875,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
+ "gdbarch_dump: has_shared_address_space = <%s>\n",
+ host_address_to_string (gdbarch->has_shared_address_space));
+ fprintf_unfiltered (file,
"gdbarch_dump: have_nonsteppable_watchpoint = %s\n",
plongest (gdbarch->have_nonsteppable_watchpoint));
fprintf_unfiltered (file,
@@ -3405,6 +3412,23 @@ set_gdbarch_has_global_breakpoints (stru
gdbarch->has_global_breakpoints = has_global_breakpoints;
}

+int
+gdbarch_has_shared_address_space (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->has_shared_address_space != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_has_shared_address_space called\n");
+ return gdbarch->has_shared_address_space (gdbarch);
+}
+
+void
+set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch,
+ gdbarch_has_shared_address_space_ftype has_shared_address_space)
+{
+ gdbarch->has_shared_address_space = has_shared_address_space;
+}
+

/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/gdbarch.h 2009-06-15 15:24:22.000000000 +0100
@@ -878,6 +878,12 @@ extern void set_gdbarch_has_global_solis
extern int gdbarch_has_global_breakpoints (struct gdbarch *gdbarch);
extern void set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch, int has_global_breakpoints);

+/* True if inferiors share an address space (e.g., uClinux). */
+
+typedef int (gdbarch_has_shared_address_space_ftype) (struct gdbarch *gdbarch);
+extern int gdbarch_has_shared_address_space (struct gdbarch *gdbarch);
+extern void set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch, gdbarch_has_shared_address_space_ftype *has_shared_address_space);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);

Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/gdbarch.sh 2009-06-15 15:24:22.000000000 +0100
@@ -742,6 +742,9 @@ v:int:has_global_solist:::0:0::0
# visible to all address spaces automatically. For such cases,
# this property should be set to true.
v:int:has_global_breakpoints:::0:0::0
+
+# True if inferiors share an address space (e.g., uClinux).
+m:int:has_shared_address_space:void:::default_has_shared_address_space::0
EOF
}

Index: src/gdb/linux-tdep.c
===================================================================
--- src.orig/gdb/linux-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/linux-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -20,6 +20,9 @@
#include "defs.h"
#include "gdbtypes.h"
#include "linux-tdep.h"
+#include "auxv.h"
+#include "target.h"
+#include "elf/common.h"

/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
@@ -137,3 +140,18 @@ linux_get_siginfo_type (struct gdbarch *

return siginfo_type;
}
+
+int
+linux_has_shared_address_space (void)
+{
+ /* Determine whether we are running on uClinux or normal Linux
+ kernel. */
+ CORE_ADDR dummy;
+ int target_is_uclinux;
+
+ target_is_uclinux
+ = (target_auxv_search (&current_target, AT_NULL, &dummy) > 0
+ && target_auxv_search (&current_target, AT_PAGESZ, &dummy) == 0);
+
+ return target_is_uclinux;
+}
Index: src/gdb/record.c
===================================================================
--- src.orig/gdb/record.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/record.c 2009-06-15 15:24:22.000000000 +0100
@@ -608,15 +608,18 @@ record_wait (struct target_ops *ops,
if (status->kind == TARGET_WAITKIND_STOPPED
&& status->value.sig == TARGET_SIGNAL_TRAP)
{
+ struct regcache *regcache;
+
/* Check if there is a breakpoint. */
registers_changed ();
- tmp_pc = regcache_read_pc (get_current_regcache ());
- if (breakpoint_inserted_here_p (tmp_pc))
+ regcache = get_current_regcache ();
+ tmp_pc = regcache_read_pc (regcache);
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
/* There is a breakpoint. */
- CORE_ADDR decr_pc_after_break =
- gdbarch_decr_pc_after_break
- (get_regcache_arch (get_current_regcache ()));
+ CORE_ADDR decr_pc_after_break
+ = gdbarch_decr_pc_after_break (get_regcache_arch (regcache));
if (decr_pc_after_break)
{
regcache_write_pc (get_thread_regcache (ret),
@@ -658,7 +661,8 @@ record_wait (struct target_ops *ops,
if (execution_direction == EXEC_FORWARD)
{
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (tmp_pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@@ -783,7 +787,8 @@ record_wait (struct target_ops *ops,

/* check breakpoint */
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (tmp_pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
Index: src/gdb/mem-break.c
===================================================================
--- src.orig/gdb/mem-break.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/mem-break.c 2009-06-15 15:24:22.000000000 +0100
@@ -54,6 +54,8 @@ default_memory_insert_breakpoint (struct
if (bp == NULL)
error (_("Software breakpoints not implemented for this target."));

+ bp_tgt->placed_address_space = current_symbol_space->aspace;
+
/* Save the memory contents. */
bp_tgt->shadow_len = bp_tgt->placed_size;
val = target_read_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
Index: src/gdb/testsuite/gdb.base/foll-vfork.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-vfork.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-vfork.exp 2009-06-15 15:24:22.000000000 +0100
@@ -93,10 +93,10 @@ proc check_vfork_catchpoints {} {
proc vfork_parent_follow_through_step {} {
global gdb_prompt

- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, vfork through step"}
- timeout {fail "set follow parent, vfork through step"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, vfork through step"}
+ timeout {fail "set follow-fork parent, vfork through step"}
}
send_gdb "next\n"
gdb_expect {
@@ -116,10 +116,10 @@ proc vfork_parent_follow_to_bp {} {
global gdb_prompt
global srcfile

- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, vfork to bp"}
- timeout {fail "set follow parent, vfork to bp"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, vfork to bp"}
+ timeout {fail "set follow-fork parent, vfork to bp"}
}
send_gdb "break ${srcfile}:18\n"
gdb_expect {
@@ -144,14 +144,14 @@ proc vfork_and_exec_child_follow_to_main
global gdb_prompt
global binfile

- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, vfork and exec to main bp"}
- timeout {fail "set follow child, vfork and exec to main bp"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec to main bp"}
+ timeout {fail "set follow-fork child, vfork and exec to main bp"}
}
send_gdb "continue\n"
gdb_expect {
- -re "Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
+ -re "Attaching after.* vfork to.*xecuting new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
{pass "vfork and exec child follow, to main bp"}
-re "$gdb_prompt $" {fail "vfork and exec child follow, to main bp"}
timeout {fail "(timeout) vfork and exec child follow, to main bp" }
@@ -193,7 +193,7 @@ proc vfork_and_exec_child_follow_through
# This test cannot be performed prior to HP-UX 10.30, because ptrace-based
# debugging of a vforking program basically doesn't allow the child to do
# things like hit a breakpoint between a vfork and exec. This means that
-# saying "set follow child; next" at a vfork() call won't work, because
+# saying "set follow-fork child; next" at a vfork() call won't work, because
# the implementation of "next" sets a "step resume" breakpoint at the
# return from the vfork(), which the child will hit on its way to exec'ing.
#
@@ -202,10 +202,10 @@ proc vfork_and_exec_child_follow_through
return 0
}

- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, vfork and exec through step"}
- timeout {fail "set follow child, vfork and exec through step"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec through step"}
+ timeout {fail "set follow-fork child, vfork and exec through step"}
}
send_gdb "next\n"
gdb_expect {
@@ -248,10 +248,10 @@ proc tcatch_vfork_then_parent_follow {}
global gdb_prompt
global srcfile

- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, tcatch vfork"}
- timeout {fail "set follow parent, tcatch vfork"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, tcatch vfork"}
+ timeout {fail "set follow-fork parent, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {
@@ -294,10 +294,10 @@ proc tcatch_vfork_then_child_follow {} {
global srcfile
global srcfile2

- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, tcatch vfork"}
- timeout {fail "set follow child, tcatch vfork"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, tcatch vfork"}
+ timeout {fail "set follow-fork child, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {
Index: src/gdb/testsuite/gdb.base/foll-exec.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-exec.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-exec.exp 2009-06-15 15:24:22.000000000 +0100
@@ -152,7 +152,7 @@ proc do_exec_tests {} {
#
send_gdb "next\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execlp call"}
-re "$gdb_prompt $" {fail "step through execlp call"}
timeout {fail "(timeout) step through execlp call"}
@@ -230,7 +230,7 @@ proc do_exec_tests {} {
setup_xfail hppa2.0w-hp-hpux* CLLbs16760
send_gdb "continue\n"
gdb_expect {
- -re ".*Executing new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
+ -re ".*xecuting new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
{pass "hit catch exec"}
-re "$gdb_prompt $" {fail "hit catch exec"}
timeout {fail "(timeout) hit catch exec"}
@@ -299,7 +299,7 @@ proc do_exec_tests {} {
#
send_gdb "next 2\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execl call"}
-re "$gdb_prompt $" {fail "step through execl call"}
timeout {fail "(timeout) step through execl call"}
@@ -353,7 +353,7 @@ proc do_exec_tests {} {
}
send_gdb "next\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execv call"}
-re "$gdb_prompt $" {fail "step through execv call"}
timeout {fail "(timeout) step through execv call"}
@@ -394,7 +394,7 @@ proc do_exec_tests {} {
#
send_gdb "continue\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "continue through exec"}
-re "$gdb_prompt $" {fail "continue through exec"}
timeout {fail "(timeout) continue through exec"}
Index: src/gdb/testsuite/gdb.base/foll-fork.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-fork.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-fork.exp 2009-06-15 15:24:22.000000000 +0100
@@ -64,7 +64,7 @@ proc check_fork_catchpoints {} {
proc default_fork_parent_follow {} {
global gdb_prompt

- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "default show parent follow, no catchpoints"}
@@ -88,12 +88,12 @@ proc default_fork_parent_follow {} {
proc explicit_fork_parent_follow {} {
global gdb_prompt

- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent"}
+ timeout {fail "(timeout) set follow-fork parent"}
}
- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "explicit show parent follow, no catchpoints"}
@@ -117,12 +117,12 @@ proc explicit_fork_parent_follow {} {
proc explicit_fork_child_follow {} {
global gdb_prompt

- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
+ -re "$gdb_prompt $" {pass "set follow-fork child"}
+ timeout {fail "(timeout) set follow-fork child"}
}
- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\"..*$gdb_prompt $"\
{pass "explicit show child follow, no catchpoints"}
@@ -131,7 +131,7 @@ proc explicit_fork_child_follow {} {
}
send_gdb "next 2\n"
gdb_expect {
- -re "Attaching after fork to.*$gdb_prompt $"\
+ -re "Attaching after.* fork to.*$gdb_prompt $"\
{pass "explicit child follow, no catchpoints"}
-re "$gdb_prompt $" {fail "explicit child follow, no catchpoints"}
timeout {fail "(timeout) explicit child follow, no catchpoints"}
@@ -185,24 +185,24 @@ proc catch_fork_child_follow {} {
}
}

- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
+ -re "$gdb_prompt $" {pass "set follow-fork child"}
+ timeout {fail "(timeout) set follow-fork child"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
- {pass "set follow child, tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
+ {pass "set follow-fork child, tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, tbreak"}
+ timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
- -re "Attaching after fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
- {pass "set follow child, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
- timeout {fail "(timeout) set follow child, hit tbreak"}
+ -re "Attaching after.* fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
+ {pass "set follow-fork child, hit tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, hit tbreak"}
+ timeout {fail "(timeout) set follow-fork child, hit tbreak"}
}
# The parent has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@@ -215,12 +215,12 @@ proc catch_fork_child_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
- {pass "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
+ {pass "set follow-fork child, cleanup"}
+ timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}
- -re "$gdb_prompt $" {fail "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, cleanup"}
+ timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}

@@ -244,7 +244,7 @@ proc catch_fork_unpatch_child {} {
"Breakpoint .*file .*$srcfile, line .*" \
"unpatch child, breakpoint at exit call"

- gdb_test "set follow child" "" "unpatch child, set follow child"
+ gdb_test "set follow-fork child" "" "unpatch child, set follow-fork child"

set test "unpatch child, unpatched parent breakpoints from child"
gdb_test_multiple "continue" $test {
@@ -297,24 +297,24 @@ proc tcatch_fork_parent_follow {} {
-re "$gdb_prompt $" {fail "explicit parent follow, tcatch fork"}
timeout {fail "(timeout) explicit parent follow, tcatch fork"}
}
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent"}
+ timeout {fail "(timeout) set follow-fork parent"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
- {pass "set follow parent, tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
+ {pass "set follow-fork parent, tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, tbreak"}
+ timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
-re ".*Detaching after fork from.* at .*$bp_after_fork.*$gdb_prompt $"\
- {pass "set follow parent, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, hit tbreak"}
- timeout {fail "(timeout) set follow parent, hit tbreak"}
+ {pass "set follow-fork parent, hit tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, hit tbreak"}
+ timeout {fail "(timeout) set follow-fork parent, hit tbreak"}
}
# The child has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@@ -327,12 +327,12 @@ proc tcatch_fork_parent_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
- {pass "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
+ {pass "set follow-fork parent, cleanup"}
+ timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}
- -re "$gdb_prompt $" {fail "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, cleanup"}
+ timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}

@@ -349,35 +349,35 @@ A fork or vfork creates a new process.
.*child - the new process is debugged after a fork.*
The unfollowed process will continue to run..*
By default, the debugger will follow the parent process..*$gdb_prompt $"\
- { pass "help set follow" }
+ { pass "help set follow-fork" }
-re "$gdb_prompt $" { fail "help set follow" }
- timeout { fail "(timeout) help set follow" }
+ timeout { fail "(timeout) help set follow-fork" }
}

# Verify that we can set follow-fork-mode, using an abbreviation
# for both the flag and its value.
#
- send_gdb "set follow ch\n"
- send_gdb "show fol\n"
+ send_gdb "set follow-fork ch\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\".*$gdb_prompt $"\
- {pass "set follow, using abbreviations"}
- timeout {fail "(timeout) set follow, using abbreviations"}
+ {pass "set follow-fork, using abbreviations"}
+ timeout {fail "(timeout) set follow-fork, using abbreviations"}
}

# Verify that we cannot set follow-fork-mode to nonsense.
#
- send_gdb "set follow chork\n"
+ send_gdb "set follow-fork chork\n"
gdb_expect {
-re "Undefined item: \"chork\".*$gdb_prompt $"\
- {pass "set follow to nonsense is prohibited"}
- -re "$gdb_prompt $" {fail "set follow to nonsense is prohibited"}
- timeout {fail "(timeout) set follow to nonsense is prohibited"}
+ {pass "set follow-fork to nonsense is prohibited"}
+ -re "$gdb_prompt $" {fail "set follow-fork to nonsense is prohibited"}
+ timeout {fail "(timeout) set follow-fork to nonsense is prohibited"}
}
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow to nonsense is prohibited (reset parent)"}
- timeout {fail "set follow to nonsense is prohibited (reset parent)"}
+ -re "$gdb_prompt $" {pass "set follow-fork to nonsense is prohibited (reset parent)"}
+ timeout {fail "set follow-fork to nonsense is prohibited (reset parent)"}
}

# Check that fork catchpoints are supported, as an indicator for whether
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/Makefile.in 2009-06-15 15:24:22.000000000 +0100
@@ -661,7 +661,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
serial.c ser-base.c ser-unix.c \
solib.c solib-null.c source.c \
stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
- symtab.c \
+ symspace.c symtab.c \
target.c target-descriptions.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
@@ -781,7 +781,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
blockframe.o breakpoint.o findvar.o regcache.o \
charset.o disasm.o dummy-frame.o dfp.o \
source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
- block.o symtab.o symfile.o symmisc.o linespec.o dictionary.o \
+ block.o symspace.o symtab.o symfile.o symmisc.o linespec.o dictionary.o \
infcall.o \
infcmd.o infrun.o \
expprint.o environ.o stack.o thread.o \
Index: src/gdb/symspace.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.c 2009-06-15 15:54:30.000000000 +0100
@@ -0,0 +1,709 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "solib.h"
+#include "gdbthread.h"
+
+/* The last symbol space number assigned. */
+int last_symbol_space_num = 0;
+
+/* The head of the symbol spaces list. */
+struct symbol_space *symbol_spaces;
+
+/* Pointer to the current symbol space. */
+struct symbol_space *current_symbol_space;
+
+/* The last address space number assigned. */
+static int highest_address_space_num;
+
+struct address_space
+{
+ int num;
+};
+
+struct address_space *
+new_address_space (void)
+{
+ struct address_space *aspace;
+
+ aspace = XZALLOC (struct address_space);
+ aspace->num = ++highest_address_space_num;
+
+ return aspace;
+}
+
+struct address_space *
+maybe_new_address_space (void)
+{
+ int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
+
+ if (shared_aspace)
+ {
+ /* Just return the first in the list. */
+ return symbol_spaces->aspace;
+ }
+
+ return new_address_space ();
+}
+
+void
+free_address_space (struct address_space *aspace)
+{
+ xfree (aspace);
+}
+
+static void
+init_address_spaces (void)
+{
+ highest_address_space_num = 0;
+}
+
+void
+set_symbol_space_name (struct symbol_space *sspace, const char *name)
+{
+ sspace->name = xstrdup (name);
+}
+
+struct symbol_space *
+add_symbol_space (struct address_space *aspace)
+{
+ struct symbol_space *sspace;
+
+ sspace = XZALLOC (struct symbol_space);
+
+ sspace->num = ++last_symbol_space_num;
+ sspace->name = xstrdup ("<unnamed>");
+ sspace->aspace = aspace;
+
+ sspace->next = symbol_spaces;
+ symbol_spaces = sspace;
+
+ return sspace;
+}
+
+static void
+release_symbol_space (struct symbol_space *sspace)
+{
+ struct cleanup *old_chain = save_current_symbol_space ();
+
+ gdb_assert (sspace != current_symbol_space);
+
+ set_current_symbol_space (sspace);
+
+ breakpoint_symbol_space_exit (sspace);
+ no_shared_libraries (NULL, 0);
+ exec_close_1 ();
+ free_all_objfiles ();
+ if (!gdbarch_has_shared_address_space (target_gdbarch))
+ free_address_space (sspace->aspace);
+ resize_section_table (&sspace->target_sections,
+ -resize_section_table (&sspace->target_sections, 0));
+ xfree (sspace->name);
+ xfree (sspace);
+
+ do_cleanups (old_chain);
+}
+
+void
+remove_symbol_space (struct symbol_space *sspace)
+{
+ struct symbol_space *ss, **ss_link;
+
+ ss = symbol_spaces;
+ ss_link = &symbol_spaces;
+ while (ss)
+ {
+ if (ss != sspace)
+ {
+ ss_link = &ss->next;
+ ss = *ss_link;
+ continue;
+ }
+
+ *ss_link = ss->next;
+
+ release_symbol_space (ss);
+ ss = *ss_link;
+ }
+}
+
+struct symbol_space *
+clone_symbol_space (struct symbol_space *dest, struct symbol_space *src)
+{
+ struct symbol_space *new_sspace;
+ struct cleanup *old_chain;
+
+ old_chain = save_current_symbol_space ();
+
+ set_current_symbol_space (dest);
+
+ if (src->ebfd)
+ exec_file_attach (bfd_get_filename (src->ebfd), 0);
+
+ if (src->symfile_objfile_1)
+ symbol_file_add_main (src->symfile_objfile_1->name, 0);
+
+ dest->name = xstrdup (src->name);
+
+ do_cleanups (old_chain);
+
+ return dest;
+}
+
+void
+set_current_symbol_space (struct symbol_space *sspace)
+{
+ if (current_symbol_space == sspace)
+ return;
+
+ gdb_assert (sspace != NULL);
+
+ current_symbol_space = sspace;
+
+ /* Different symbols change our view of the frame chain. */
+ reinit_frame_cache ();
+}
+
+static void
+restore_symbol_space (void *arg)
+{
+ struct symbol_space *saved_sspace = arg;
+ set_current_symbol_space (saved_sspace);
+}
+
+/* Save the current symbol space so that it may be restored by a later
+ call to do_cleanups. Returns the struct cleanup pointer needed for
+ later doing the cleanup. */
+
+struct cleanup *
+save_current_symbol_space (void)
+{
+ struct cleanup *old_chain = make_cleanup (restore_symbol_space,
+ current_symbol_space);
+ return old_chain;
+}
+
+/* Look for symbol space number NUM. */
+
+struct symbol_space *
+find_symbol_space_by_num (int num)
+{
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->num == num)
+ return sspace;
+
+ return NULL;
+}
+
+static void
+symbol_space_command (char *args, int from_tty)
+{
+ int num;
+ struct inferior *inf;
+ struct symbol_space *sspace;
+
+ if (symbol_spaces == NULL)
+ error (_("No spaces"));
+
+ num = parse_and_eval_long (args);
+
+ sspace = find_symbol_space_by_num (num);
+
+ if (sspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+
+ set_current_symbol_space (sspace);
+
+ inf = find_inferior_for_symbol_space (sspace);
+
+ if (inf == NULL)
+ {
+ switch_to_thread (null_ptid);
+
+ if (sspace->ebfd)
+ printf_filtered (_("[Switching to sspace %d (%s)]\n"),
+ sspace->num, bfd_get_filename (sspace->ebfd));
+ else
+ printf_filtered (_("[Switching to sspace %d]\n"), sspace->num);
+ return;
+ }
+
+ if (inf->pid != ptid_get_pid (inferior_ptid))
+ {
+ struct thread_info *tp;
+
+ tp = any_thread_of_process (inf->pid);
+ if (!tp)
+ {
+ switch_to_thread (null_ptid);
+ error (_("Inferior has no threads."));
+ }
+
+ switch_to_thread (tp->ptid);
+ }
+
+ printf_filtered (_("[Switching to thread %d (%s)] "),
+ pid_to_thread_id (inferior_ptid),
+ target_pid_to_str (inferior_ptid));
+
+ if (is_running (inferior_ptid))
+ ui_out_text (uiout, "(running)\n");
+ else
+ {
+ ui_out_text (uiout, "\n");
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ }
+}
+
+void
+add_symbol_space_command (char *args, int from_tty)
+{
+ int i, copies = 1;
+ char *namebase = NULL, *exec = NULL;
+ char **argv;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ if (args)
+ {
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
+
+ for (; *argv != NULL; argv++)
+ {
+ if (**argv == '-')
+ {
+ if (strcmp (*argv, "-copies") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -copies");
+ copies = parse_and_eval_long (*argv);
+ }
+ else if (strcmp (*argv, "-name") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -name");
+ namebase = *argv;
+ }
+ else if (strcmp (*argv, "-exec") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -exec");
+ exec = *argv;
+ }
+ }
+ else
+ error (_("Invalid argument"));
+ }
+ }
+
+ save_current_symbol_space ();
+ make_cleanup_restore_current_thread ();
+
+ for (i = 0; i < copies; ++i)
+ {
+ struct address_space *aspace;
+ struct symbol_space *sspace;
+ char *namebuf;
+
+ aspace = maybe_new_address_space ();
+ sspace = add_symbol_space (aspace);
+ set_current_symbol_space (sspace);
+ namebuf = xstrprintf ("%s%d",
+ namebase ? namebase : "sspace",
+ sspace->num);
+ set_symbol_space_name (sspace, namebuf);
+ printf_filtered ("Added symbol space %d (%s)\n",
+ sspace->num, sspace->name);
+
+ switch_to_thread (null_ptid);
+ if (exec)
+ exec_file_attach (exec, from_tty);
+
+ xfree (namebuf);
+ }
+
+ do_cleanups (old_chain);
+
+ printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+void
+clone_symbol_space_command (char *args, int from_tty)
+{
+ int i, copies = 1;
+ char *namebase = NULL;
+ char **argv;
+ struct symbol_space *orgspace = NULL;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ if (args)
+ {
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
+
+ for (; *argv != NULL; argv++)
+ {
+ if (**argv == '-')
+ {
+ if (strcmp (*argv, "-copies") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -copies");
+ copies = parse_and_eval_long (*argv);
+
+ if (copies < 0)
+ error (_("Invalid copies number"));
+ }
+ else if (strcmp (*argv, "-name") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -name");
+ namebase = *argv;
+ }
+ }
+ else
+ {
+ if (orgspace == NULL)
+ {
+ int num;
+
+ num = parse_and_eval_long (*argv);
+ orgspace = find_symbol_space_by_num (num);
+
+ if (orgspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+ continue;
+ }
+ else
+ error (_("Invalid argument"));
+ }
+ }
+ }
+
+ if (orgspace == NULL)
+ orgspace = current_symbol_space;
+
+ save_current_space_and_thread ();
+
+ for (i = 0; i < copies; ++i)
+ {
+ struct address_space *aspace;
+ struct symbol_space *sspace;
+ char *namebuf;
+
+ aspace = maybe_new_address_space ();
+ sspace = add_symbol_space (aspace);
+
+ namebuf = xstrprintf ("%s%d",
+ namebase ? namebase : "sspace",
+ sspace->num);
+ set_symbol_space_name (sspace, namebuf);
+ printf_filtered ("Added symbol space %d (%s).\n",
+ sspace->num, sspace->name);
+
+ switch_to_thread (null_ptid);
+ clone_symbol_space (sspace, orgspace);
+
+ set_symbol_space_name (sspace, namebuf);
+ xfree (namebuf);
+ }
+
+ do_cleanups (old_chain);
+
+ printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+void
+remove_symbol_space_command (char *args, int from_tty)
+{
+ int num;
+ struct inferior *inf;
+ struct symbol_space *sspace;
+
+ num = parse_and_eval_long (args);
+ sspace = find_symbol_space_by_num (num);
+
+ if (sspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+
+ if (sspace == current_symbol_space)
+ error (_("Can't remove current symbol space"));
+
+ inf = find_inferior_for_symbol_space (sspace);
+
+ if (inf != NULL)
+ error (_("Can't remove symbol space with live inferiors"));
+
+ remove_symbol_space (sspace);
+}
+
+static int
+sspace_empty_p (struct symbol_space *sspace)
+{
+ struct inferior *inf;
+
+ if (find_inferior_for_symbol_space (sspace) != NULL)
+ return 0;
+
+ return 1;
+}
+
+static void
+prune_symbol_spaces (void)
+{
+ struct symbol_space *ss, **ss_link;
+ struct symbol_space *curr = current_symbol_space;
+
+ ss = symbol_spaces;
+ ss_link = &symbol_spaces;
+ while (ss)
+ {
+ if (ss == curr
+ || !ss->removable
+ || !sspace_empty_p (ss))
+ {
+ ss_link = &ss->next;
+ ss = *ss_link;
+ continue;
+ }
+
+ release_symbol_space (ss);
+
+ *ss_link = ss->next;
+ ss = *ss_link;
+ }
+}
+
+void
+print_symbol_space (struct ui_out *uiout, int requested)
+{
+ struct symbol_space *sspace;
+ int count = 0;
+ struct cleanup *old_chain;
+
+ prune_symbol_spaces ();
+
+ /* Compute number of inferiors we will print. */
+ ALL_SSPACES (sspace)
+ {
+ if (requested != -1 && sspace->num != requested)
+ continue;
+
+ ++count;
+ }
+
+ if (count == 0)
+ {
+ ui_out_message (uiout, 0, "No symbol spaces.\n");
+ return;
+ }
+
+ old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, count,
+ "sspaces");
+ ui_out_table_header (uiout, 1, ui_left, "current", "");
+ ui_out_table_header (uiout, 4, ui_left, "id", "Id");
+ ui_out_table_header (uiout, 17, ui_left, "exec", "Main Program");
+ ui_out_table_body (uiout);
+
+ ALL_SSPACES (sspace)
+ {
+ struct cleanup *chain2;
+ struct inferior *inf;
+ int printed_header = 0;
+
+ if (requested != -1 && requested != sspace->num)
+ continue;
+
+ chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ if (sspace == current_symbol_space)
+ ui_out_field_string (uiout, "current", "*");
+ else
+ ui_out_field_skip (uiout, "current");
+
+ ui_out_field_int (uiout, "id", sspace->num);
+
+ if (sspace->ebfd)
+ ui_out_field_string (uiout, "exec",
+ bfd_get_filename (sspace->ebfd));
+ else
+ ui_out_field_skip (uiout, "exec");
+
+ printed_header = 0;
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->sspace == sspace)
+ {
+ if (!printed_header)
+ {
+ printed_header = 1;
+ printf_filtered ("\n\tBound inferiors: ID %d (%s)",
+ inf->num,
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+ }
+ else
+ printf_filtered (", ID %d (%s)",
+ inf->num,
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+ }
+
+ ui_out_text (uiout, "\n");
+ do_cleanups (chain2);
+ }
+
+ do_cleanups (old_chain);
+}
+
+int
+valid_symbol_space_id (int num)
+{
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->num == num)
+ return 1;
+
+ return 0;
+}
+
+/* Print information about currently known inferiors. */
+
+static void
+info_symbol_spaces_command (char *args, int from_tty)
+{
+ int requested = -1;
+
+ if (args && *args)
+ {
+ requested = parse_and_eval_long (args);
+ if (!valid_symbol_space_id (requested))
+ error (_("Symbol space ID %d not known."), requested);
+ }
+
+ print_symbol_space (uiout, requested);
+}
+
+int
+number_of_symbol_spaces (void)
+{
+ struct symbol_space *sspace;
+ int count = 0;
+
+ ALL_SSPACES (sspace)
+ count++;
+
+ return count;
+}
+
+void
+update_address_spaces (void)
+{
+ int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
+ struct address_space *aspace = NULL;
+ struct symbol_space *sspace;
+
+ init_address_spaces ();
+
+ ALL_SSPACES (sspace)
+ {
+ free_address_space (sspace->aspace);
+
+ if (shared_aspace)
+ {
+ if (aspace == NULL)
+ aspace = new_address_space ();
+ sspace->aspace = aspace;
+ }
+ else
+ sspace->aspace = new_address_space ();
+ }
+}
+
+struct cleanup *
+save_current_space_and_thread (void)
+{
+ struct cleanup *old_chain;
+
+ /* If restoring to null thread, we need to restore the sspace as
+ well, hence, we need to save the current symbol space first. */
+ old_chain = save_current_symbol_space ();
+ make_cleanup_restore_current_thread ();
+
+ return old_chain;
+}
+
+void
+switch_to_symbol_space_and_thread (struct symbol_space *sspace)
+{
+ if (sspace != NULL)
+ {
+ struct inferior *inf;
+
+ inf = find_inferior_for_symbol_space (sspace);
+ if (inf != NULL)
+ {
+ struct thread_info *tp;
+
+ tp = any_live_thread_of_process (inf->pid);
+
+ if (tp != NULL)
+ {
+ switch_to_thread (tp->ptid);
+ return;
+ }
+ }
+ }
+
+ switch_to_thread (null_ptid);
+ set_current_symbol_space (sspace);
+}
+
+extern initialize_file_ftype _initialize_symspace; /* -Wmissing-prototypes */
+
+void
+_initialize_symspace (void)
+{
+ add_info ("sspaces", info_symbol_spaces_command, _("\
+Info about currently known symbol spaces."));
+
+ add_com ("sspace", no_class, symbol_space_command, _("\
+Change the current symbol space."));
+
+ add_com ("add-symbol-space", no_class, add_symbol_space_command, _("\
+Add a new symbol space."));
+
+ add_com ("remove-symbol-space", no_class, remove_symbol_space_command, _("\
+Remove the symbol-space."));
+
+ add_com ("clone-symbol-space", no_class, clone_symbol_space_command, _("\
+Clone symbol space SPACE."));
+
+ current_symbol_space = add_symbol_space (new_address_space ());
+}
Index: src/gdb/symspace.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.h 2009-06-15 15:24:22.000000000 +0100
@@ -0,0 +1,262 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef SYMSPACE_H
+#define SYMSPACE_H
+
+#include "target.h"
+#include "vec.h"
+
+struct target_ops;
+struct bfd;
+struct objfile;
+struct inferior;
+struct exec;
+struct address_space;
+
+/* A symbol space represents a symbolic view of an address space.
+ Roughly speaking, it holds all the data associated with a
+ non-running-yet program (main executable, main symbols), and when
+ an inferior is running and is bound to it, includes the list of its
+ mapped in shared libraries.
+
+ In the traditional debugging scenario, there's a 1-1 correspondence
+ among symbol spaces, inferiors and address spaces, like so:
+
+ sspace1 (prog1) <--> inf1(pid1) <--> aspace1
+
+ In the case of debugging more than one traditional unix process or
+ program, we still have:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |----------------------------------------|
+ | sspace2 (prog1) | no inf yet | aspace2 |
+ |-----------------+------------+---------|
+ | sspace3 (prog2) | inf2(pid2) | aspace3 |
+ |-----------------+------------+---------|
+
+ In the former example, if inf1 forks (and GDB stays attached to
+ both processes), the new child will have its own symbol and address
+ spaces. Like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ However, had inf1 from the latter case vforked instead, it would
+ share the symbol and address spaces with its parent, until it execs
+ or exits, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ | | inf2(pid2) | |
+ |-----------------+------------+---------|
+
+ When the vfork child execs, it is finally given new symbol and
+ address spaces.
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ There are targets where the OS (if any) doesn't provide memory
+ management or VM protection, where all inferiors share the same
+ address space --- e.g. uClinux. GDB models by having all inferiors
+ share the same address space, but, giving each its own symbol
+ space, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | |
+ |-----------------+------------+ |
+ | sspace2 (prog1) | inf2(pid2) | aspace1 |
+ |-----------------+------------+ |
+ | sspace3 (prog2) | inf3(pid3) | |
+ |-----------------+------------+---------|
+
+ The address space sharing matters for run control and breakpoints
+ management. E.g., did we just hit a known breakpoint that we need
+ to step over? Is this breakpoint a duplicate of this other one, or
+ do I need to insert a trap?
+
+ Then, there are targets where all symbols look the same for all
+ inferiors, although each has its own address space, as e.g.,
+ Ericsson DICOS. In such case, the model is:
+
+ |---------+------------+---------|
+ | | inf1(pid1) | aspace1 |
+ | +------------+---------|
+ | sspace | inf2(pid2) | aspace2 |
+ | +------------+---------|
+ | | inf3(pid3) | aspace3 |
+ |---------+------------+---------|
+
+ Note however, that the DICOS debug API takes care of making GDB
+ believe that breakpoints are "global". That is, although each
+ process does have its own private copy of data symbols (just like a
+ bunch of forks), to the breakpoints module, all processes share a
+ single address space, so all breakpoints set at the same address
+ are duplicates of each other, even breakpoints set in the data
+ space (e.g., call dummy breakpoints placed on stack). This allows
+ a simplification in the spaces implementation: we avoid caring for
+ a many-many links between address and symbol spaces. Either
+ there's a single address space bound to the symbol space
+ (traditional unix/uClinux), or, in the DICOS case, the address
+ space bound to the symbol space is mostly ignored. */
+
+/* The symbol space structure. */
+
+struct symbol_space
+ {
+ /* Pointer to next in linked list. */
+ struct symbol_space *next;
+
+ /* Unique ID number. */
+ int num;
+
+ /* The name of the symbol space. */
+ char *name;
+
+ /* An abbreviated name, typically formed by pruning the directory
+ from the full name of the main executable. */
+ char *shortname;
+
+ /* The main executable loaded into this symbol space. This is
+ managed by the exec target. */
+
+ /* The BFD handle for this executable. */
+ bfd *ebfd;
+ /* The last-modified time, from when the exec was brought in. */
+ long ebfd_mtime;
+
+ /* The address space attached to this symbol space. More than one
+ symbol space may be bound to the same address space. In the
+ traditional unix-like debugging scenario, this will usually
+ match the address space bound to the inferior, and is mostly
+ used by the breakpoints module for address matches. If the
+ target shares a symbol space for all inferiors and breakpoints
+ are global, then this field is ignored (we don't currently
+ support inferiors sharing a symbol space if the target doesn't
+ make breakpoints global). */
+ struct address_space *aspace;
+
+ /* The object file that the main symbol table was loaded from
+ (e.g. the argument to the "symbol-file" or "file" command). */
+ struct objfile *symfile_objfile_1;
+
+ /* All known objfiles are kept in a linked list. This points to
+ the root of this list. */
+ struct objfile *objfiles;
+
+ /* The set of target sections matching the sections mapped into
+ this symbol space. Managed by both exec_ops and solib.c. */
+ struct target_section_table target_sections;
+
+ /* List of shared objects mapped into this space. Managed by
+ solib.c. */
+ struct so_list *so_list;
+
+ /* True if this was an auto-created sspace, e.g. created from
+ following a fork/exec; false, if this sspace was manually added
+ by the user, and should not be pruned automatically. */
+ int removable;
+ };
+
+/* The object file that the main symbol table was loaded from (e.g. the
+ argument to the "symbol-file" or "file" command). */
+
+#define symfile_objfile current_symbol_space->symfile_objfile_1
+
+/* All known objfiles are kept in a linked list. This points to the
+ root of this list. */
+#define object_files current_symbol_space->objfiles
+
+/* The set of target sections matching the sections mapped into the
+ current symbol address space. */
+#define current_target_sections (&current_symbol_space->target_sections)
+
+/* The list of all symbol spaces. There's always at least one. */
+extern struct symbol_space *symbol_spaces;
+
+/* The current symbol space. This is always non-null. */
+extern struct symbol_space *current_symbol_space;
+
+#define ALL_SSPACES(sspace) \
+ for ((sspace) = symbol_spaces; (sspace) != NULL; (sspace) = (sspace)->next)
+
+/* Add a new empty symbol space, and assign ASPACE to it. Returns the
+ pointer to the new object. */
+extern struct symbol_space *add_symbol_space (struct address_space *aspace);
+
+/* Release SSPACE and removes it from the sspace list. */
+extern void remove_symbol_space (struct symbol_space *sspace);
+
+/* Returns the number of symbol spaces listed. */
+extern int number_of_symbol_spaces (void);
+
+/* Sets the symbol space's name to NAME. A deep copy is performed on
+ NAME. */
+extern void set_symbol_space_name (struct symbol_space *sspace,
+ const char *name);
+
+/* Copies symbol space SRC to DEST. Copies the main executable file,
+ and the main symbol file. Returns DEST. */
+extern struct symbol_space *clone_symbol_space (struct symbol_space *dest,
+ struct symbol_space *src);
+
+/* Save the current symbol space in the current cleanup chain. */
+extern struct cleanup *save_current_symbol_space (void);
+
+/* Sets SSPACE as the current symbol space. It is the callers
+ responsibility to make sure that the currently selected
+ inferior/thread matches the selected symbol space. */
+extern void set_current_symbol_space (struct symbol_space *sspace);
+
+/* Saves the current thread (may be null), frame and symbol space in
+ the current cleanup chain. */
+extern struct cleanup *save_current_space_and_thread (void);
+
+/* Switches full context to symbol space SSPACE. Switches to the
+ first thread found bound to SSPACE. */
+extern void switch_to_symbol_space_and_thread (struct symbol_space *sspace);
+
+/* Create a new address space object, and add it to the list. */
+extern struct address_space *new_address_space (void);
+
+/* Maybe create a new address space object, and add it to the list, or
+ return a pointer to an existing address space, in case inferiors
+ share an address space. */
+extern struct address_space *maybe_new_address_space (void);
+
+/* Update all symbol spaces matching to address spaces. The user may
+ have created several symbol spaces, and loaded executables into
+ them before connecting to the target interface that will create the
+ inferiors. All that happens before GDB has a chance to know if the
+ inferiors will share an address space or not. Call this after
+ having connected to the target interface and having fetched the
+ target description, to fixup the symbol/address spaces
+ mappings. */
+extern void update_address_spaces (void);
+
+#endif
Index: src/gdb/arm-linux-tdep.c
===================================================================
--- src.orig/gdb/arm-linux-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/arm-linux-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -585,7 +585,7 @@ arm_linux_software_single_step (struct f
if (next_pc > 0xffff0000)
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);

- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame), next_pc);

return 1;
}
Index: src/gdb/cris-tdep.c
===================================================================
--- src.orig/gdb/cris-tdep.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/cris-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -470,7 +470,7 @@ crisv32_single_step_through_delay (struc
{
/* In delay slot - check if there's a breakpoint at the preceding
instruction. */
- if (breakpoint_here_p (erp & ~0x1))
+ if (breakpoint_here_p (get_frame_address_space (this_frame), erp & ~0x1))
ret = 1;
}
return ret;
@@ -2137,13 +2137,14 @@ cris_software_single_step (struct frame_
and possibly another one for a branch, jump, etc. */
CORE_ADDR next_pc =
(CORE_ADDR) inst_env.reg[gdbarch_pc_regnum (get_frame_arch (frame))];
- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame), next_pc);
if (inst_env.branch_found
&& (CORE_ADDR) inst_env.branch_break_address != next_pc)
{
CORE_ADDR branch_target_address
= (CORE_ADDR) inst_env.branch_break_address;
- insert_single_step_breakpoint (branch_target_address);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ branch_target_address);
}
}

Index: src/gdb/mips-tdep.c
===================================================================
--- src.orig/gdb/mips-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/mips-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -2380,7 +2380,7 @@ mips_addr_bits_remove (struct gdbarch *g
the sequence. */

static int
-deal_with_atomic_sequence (CORE_ADDR pc)
+deal_with_atomic_sequence (struct frame_info *frame, CORE_ADDR pc)
{
CORE_ADDR breaks[2] = {-1, -1};
CORE_ADDR loc = pc;
@@ -2468,7 +2468,8 @@ deal_with_atomic_sequence (CORE_ADDR pc)

/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
- insert_single_step_breakpoint (breaks[index]);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ breaks[index]);

return 1;
}
@@ -2484,12 +2485,13 @@ mips_software_single_step (struct frame_
CORE_ADDR pc, next_pc;

pc = get_frame_pc (frame);
- if (deal_with_atomic_sequence (pc))
+ if (deal_with_atomic_sequence (frame, pc))
return 1;

next_pc = mips_next_pc (frame, pc);

- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ next_pc);
return 1;
}

@@ -4665,7 +4667,7 @@ mips_single_step_through_delay (struct g
if (mips_pc_is_mips16 (pc))
return 0;

- if (!breakpoint_here_p (pc + 4))
+ if (!breakpoint_here_p (get_frame_address_space (frame), pc + 4))
return 0;

if (!safe_frame_unwind_memory (frame, pc, buf, sizeof buf))
Index: src/gdb/rs6000-aix-tdep.c
===================================================================
--- src.orig/gdb/rs6000-aix-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/rs6000-aix-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -688,7 +688,8 @@ rs6000_software_single_step (struct fram
/* ignore invalid breakpoint. */
if (breaks[ii] == -1)
continue;
- insert_single_step_breakpoint (breaks[ii]);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ breaks[ii]);
}

errno = 0; /* FIXME, don't ignore errors! */
Index: src/gdb/rs6000-tdep.c
===================================================================
--- src.orig/gdb/rs6000-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/rs6000-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -1143,7 +1143,8 @@ ppc_deal_with_atomic_sequence (struct fr

/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
- insert_single_step_breakpoint (breaks[index]);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ breaks[index]);

return 1;
}
Index: src/gdb/solib-irix.c
===================================================================
--- src.orig/gdb/solib-irix.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/solib-irix.c 2009-06-15 15:24:22.000000000 +0100
@@ -357,8 +357,11 @@ enable_break (void)
{
if (symfile_objfile != NULL)
{
+ struct frame_info *frame = get_current_frame ();
+
base_breakpoint
- = deprecated_insert_raw_breakpoint (entry_point_address ());
+ = deprecated_insert_raw_breakpoint (get_frame_address_space (frame),
+ entry_point_address ());

if (base_breakpoint != NULL)
return 1;
Index: src/gdb/sparc-tdep.c
===================================================================
--- src.orig/gdb/sparc-tdep.c 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/sparc-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -1297,10 +1297,12 @@ sparc_software_single_step (struct frame
/* Analyze the instruction at PC. */
nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
if (npc != 0)
- insert_single_step_breakpoint (npc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ npc);

if (nnpc != 0)
- insert_single_step_breakpoint (nnpc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ nnpc);

/* Assert that we have set at least one breakpoint, and that
they're not set at the same spot - unless we're going
Index: src/gdb/spu-tdep.c
===================================================================
--- src.orig/gdb/spu-tdep.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/spu-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -1306,7 +1306,8 @@ spu_software_single_step (struct frame_i
else
next_pc = (pc + 4) & (SPU_LS_SIZE - 1);

- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ next_pc);

if (is_branch (insn, &offset, &reg))
{
@@ -1322,7 +1323,8 @@ spu_software_single_step (struct frame_i

target = target & (SPU_LS_SIZE - 1);
if (target != next_pc)
- insert_single_step_breakpoint (target);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ target);
}

return 1;
Index: src/gdb/alpha-tdep.c
===================================================================
--- src.orig/gdb/alpha-tdep.c 2009-06-15 15:24:14.000000000 +0100
+++ src/gdb/alpha-tdep.c 2009-06-15 15:24:22.000000000 +0100
@@ -1482,7 +1482,8 @@ alpha_software_single_step (struct frame
pc = get_frame_pc (frame);
next_pc = alpha_next_pc (frame, pc);

- insert_single_step_breakpoint (next_pc);
+ insert_single_step_breakpoint (get_frame_address_space (frame),
+ next_pc);
return 1;
}

Index: src/gdb/testsuite/gdb.base/multi-forks.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/multi-forks.exp 2009-06-15 15:24:15.000000000 +0100
+++ src/gdb/testsuite/gdb.base/multi-forks.exp 2009-06-15 15:24:22.000000000 +0100
@@ -121,7 +121,7 @@ proc continue_to_exit_bp_loc {} {
# The result should be that each of the 4 forks returns zero.

runto_main
-gdb_test "set follow child"
+gdb_test "set follow-fork child"
continue_to_exit_bp_loc

gdb_test "print pids" "\\$.* = \\{0, 0, 0, 0\\}.*" "follow child, print pids"
@@ -130,7 +130,7 @@ gdb_test "print pids" "\\$.* = \\{0, 0,
# Result should be that none of the 4 forks returns zero.

runto_main
-gdb_test "set follow parent" "" ""
+gdb_test "set follow-fork parent" "" ""
continue_to_exit_bp_loc

gdb_test "print pids\[0\]==0 || pids\[1\]==0 || pids\[2\]==0 || pids\[3\]==0" \