This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


[ I sent this a few hours ago, but it didn't show up
in the archives.  Maybe the patch was too big. I'm splitting the patch in two now.  ]

On Friday 26 June 2009 20:08:52, Tom Tromey wrote:
> Pedro> But I had already. ?:-) ?Or, do you mean to split that change out
> Pedro> of the patch? ?I can do that. ?I think that would be good idea.
> 
> I thought your patch had this change in one place but not "info
> inferiors". ?Maybe I missed it. ?Anyway, don't worry about it, I'll
> mark this note and go back and check once everything goes in.

Yeah, here's what it looks like with the patch applied:

(top-gdb) info inferiors
  Id   Target ID         SSpace Main Program
* 1    process 22453     1      /home/pedro/gdb/sspaces/build/gdb/gdb

Compared to the current:

(top-gdb) info inferiors
Cur   Id     PID
  *    1   24950


I think that it looks nicer and more consistent with "info threads"
(minus column headers :-) )

(top-gdb) info threads
* 1 Thread 0x7ffff7fd36e0 (LWP 26685)  main (argc=1, argv=0x7fffffffe3a8) at ../../src/gdb/gdb.c:28

> 
> Pedro> I'm now working on cleaning up a bit the patch and fixing the
> Pedro> random crashes I mentioned, and I'll be posting an updated
> Pedro> patch soon.
> 
> I'm looking forward to it.
> 

Here's the updated patch.  I went through and added a bunch
of comments, cleaned it up some, tweaked a bit how vfork is handled,
fixed all the heisenbugs I was aware of, added a couple of basic
tests, docs, and wrote a change log entry (that, was a pain).  The
patch does contain vestigial bits from the multiprocess branch in cvs,
where I had originaly based on.

The user interface is still the same as I showed in:

 http://sourceware.org/ml/gdb-patches/2009-06/msg00388.html

This still applies on top of the other patch to move the
multi-forks support to the multi-inferior framework, which
I've just posted an updated patch of: 

 http://sourceware.org/ml/gdb-patches/2009-07/msg00033.html

Part 2 of the patch is unchanged, but I'll repost it for
ease of trying it out.

Admitably, the tests and docs aren't much yet, but at least
there's something already!  :-)


I hope the comments I've added make things look digestable.
If not, ask away, and I'll update whatever's needed.


Would be nice if people gave it a shot and experimented a bit.
I'd like to hear how it feels.  :-)

(this is part 1 of the patch.  Part 2 follow shortly.)

-- 
Pedro Alves

gdb/
2009-07-01  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	Add multi-executable/process support to GDB.

	* Makefile.in (SFILES): Add symspace.c.
	(COMMON_OBS): Add symspace.o.
	* symspace.h: New.
	* symspace.c: New.

	* breakpoint.h (struct bp_target_info) <placed_address_space>: New
	field.
	(struct bp_location) <sspace>: New field.
	(struct breakpoint) <sspace>: New field.
	(bpstat_stop_status, breakpoint_here_p)
	(moribund_breakpoint_here_p, breakpoint_inserted_here_p)
	(regular_breakpoint_inserted_here_p)
	(software_breakpoint_inserted_here_p, breakpoint_thread_match)
	(set_default_breakpoint): Adjust prototypes.
	(remove_breakpoints_pid, breakpoint_symbol_space_exit): Declare.
	(insert_single_step_breakpoint, deprecated_insert_raw_breakpoint):
	Adjust prototypes.
	* breakpoint.c (default_breakpoint_sspace): New.
	(breakpoint_restore_shadows): Skip if the address space doesn't
	match.
	(update_watchpoint): Record the frame's symbol space in the
	breakpoint location.
	(insert_bp_location): Record the address space in target_info.
	Adjust to pass the symbol space to solib_name_from_address.
	(breakpoint_symbol_space_exit): New.
	(insert_breakpoint_locations): Switch the symbol space and thread
	when inserting breakpoints.
	(remove_breakpoints_pid): New.
	(reattach_breakpoints): Switch to a thread of PID.  Ignore
	breakpoints of other symbol spaces.
	(create_internal_breakpoint): Store the symbol space in the sal.
	(create_longjmp_master_breakpoint): Iterate over all symbol
	spaces.
	(update_breakpoints_after_exec): Ignore breakpoints for other
	symbol spaces.
	(remove_breakpoint): Rename to ...
	(remove_breakpoint_1): ... this.  Pass the breakpoints symbol
	space to solib_name_from_address.
	(remove_breakpoint): New.
	(mark_breakpoints_out): Ignore breakpoints from other symbol
	spaces.
	(breakpoint_init_inferior): Ditto.
	(breakpoint_here_p): Add an address space argument and adjust to
	use breakpoint_address_match.
	(moribund_breakpoint_here_p): Ditto.
	(regular_breakpoint_inserted_here_p): Ditto.
	(breakpoint_inserted_here_p): Ditto.
	(software_breakpoint_inserted_here_p): Ditto.
	(breakpoint_thread_match): Ditto.
	(bpstat_check_location): Ditto.
	(bpstat_stop_status): Ditto.
	(print_breakpoint_location): If there's a location to print,
	switch the current symbol space.
	(print_one_breakpoint_location): Add `allflag' argument.
	(print_one_breakpoint): Ditto.  Adjust.
	(do_captured_breakpoint_query): Adjust.
	(breakpoint_1): Adjust.
	(breakpoint_has_pc): Also match the symbol space.
	(describe_other_breakpoints): Add a symbol space argument and
	adjust.
	(set_default_breakpoint): Add a symbol space argument.  Set
	default_breakpoint_sspace.
	(breakpoint_address_match): New.
	(check_duplicates_for): Add an address space argument, and adjust.
	(set_raw_breakpoint): Record the symbol space in the location and
	in the breakpoint.
	(set_longjmp_breakpoint): Skip longjmp master breakpoints from
	other symbol spaces.
	(remove_thread_event_breakpoints, remove_solib_event_breakpoints)
	(disable_breakpoints_in_shlibs): Skip breakpoints from other
	symbol spaces.
	(disable_breakpoints_in_unloaded_shlib): Match symbol spaces.
	(create_catchpoint): Set the symbol space in the sal.
	(clone_momentary_breakpoint): Also copy the symbol space.
	(add_location_to_breakpoint): Set the location's symbol space.
	(bp_loc_is_permanent): Switch thread and symbol space.
	(create_breakpoint): Adjust.
	(expand_line_sal_maybe): Expand comment to mention symbol spaces.
	Switch thread and symbol space when reading memory.
	(parse_breakpoint_sals): Set the symbol space in the sal.
	(break_command_really): Ditto.
	(skip_prologue_sal): Switch and space.
	(resolve_sal_pc): Ditto.
	(watch_command_1): Record the symbol space in the sal.
	(create_ada_exception_breakpoint): Adjust.
	(clear_command): Adjust.  Match symbol spaces.
	(update_global_location_list): Use breakpoint_address_match.
	(breakpoint_re_set_one): Switch thread and space.
	(breakpoint_re_set): Save symbol space.
	(breakpoint_re_set_thread): Also reset the symbol space.
	(deprecated_insert_raw_breakpoint): Add an address space argument.
	Adjust.
	(insert_single_step_breakpoint): Ditto.
	(single_step_breakpoint_inserted_here_p): Ditto.
	
	* exec.h: Include "symspace.h".
	(exec_bfd, exec_bfd_mtime): New defines.
	(exec_close_1): Declare.
	* exec.c: Include "gdbthread.h" and "symspace.h".
	(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
	(using_exec_ops): New.
	(exec_close_1): Make public.
	(exec_close): Add description.  Remove target sections and close
	executables from all symbol spaces.
	(exec_file_attach): Add comment.
	(add_target_sections): Check on `using_exec_ops' to check if the
	target should be pushed.
	(remove_target_sections): Only unpush the target if there are no
	more target sections in any symbol space.
	* gdbcore.h: Include "exec.h".
	(exec_bfd, exec_bfd_mtime): Remove declarations.

	* frame.h (get_frame_symbol_space, get_frame_address_space)
	(frame_unwind_symbol_space): Declare.
	* frame.c (struct frame_info) <sspace, aspace>: New fields.
	(create_sentinel_frame): Add symbol space argument.  Set the
	sspace and aspace fields of the frame object.
	(get_current_frame, create_new_frame): Adjust.
	(get_frame_symbol_space): New.
	(frame_unwind_symbol_space): New.
	(get_frame_address_space): New.
	* stack.c (print_frame_info): Adjust.
	(print_frame): Use the frame's symbol space.

	* gdbthread.h (any_live_thread_of_process): Declare.
	* thread.c (any_live_thread_of_process): New.
	(switch_to_thread): Switch the symbol space as well.
	(restore_selected_frame): Don't warn if trying to restore frame
	level 0.

	* inferior.h: Include "symspace.h".
	(detach_fork): Declare.
	(struct inferior) <aspace, sspace, vfork_parent, vfork_child>
	<pending_detach, waiting_for_vfork_done>: New fields.
	(find_inferior_pid): Typo.
	(find_inferior_id, find_inferior_for_symbol_space): Declare.
	(inferior_list): Declare.
	* inferior.c: Include "exec.h".
	(inferior_list): Make public.
	(delete_inferior_1): Always delete thread silently.
	(find_inferior_id): Make public.
	(find_inferior_for_symbol_space): New.
	(print_inferior): Align columns left.  Remove header for the the
	"current" column.  Add symbol space and executable columns.  Print
	vfork parent/child relationships.  Print if there's no selected
	inferior.

	* objfiles.h: Include "symspace.h".
	(struct objfile) <sspace>: New fields.
	(symfile_objfile, object_files): Don't declare.
	(ALL_SSPACE_OBJFILES): New.
	(ALL_SSPACE_OBJFILES_SAFE): New.
	(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
	(ALL_SSPACE_SYMTABS): New.
	(ALL_PRIMARY_SYMTABS): Adjust.
	(ALL_SSPACE_PRIMARY_SYMTABS): New.
	(ALL_PSYMTABS): Adjust.
	(ALL_SSPACE_PSYMTABS): New.
	* objfiles.c (object_files): Delete.
	(symfile_objfile): Delete.
	(allocate_objfile): Set the objfiles symbol space.

	* linespec.c (decode_all_digits, decode_dollar): Set the sal's
	symbol space.
	* source.c (current_source_sspace): New.
	(get_current_source_symtab_and_line): Set the sal's symbol space.
	(set_current_source_symtab_and_line): Set current_source_sspace.
	(select_source_symtab): Ditto.  Use ALL_OBJFILES.
	(forget_cached_source_info): Iterate over all symbol spaces.
	* symfile.c (clear_symtab_users): Adjust.
	* symmisc.c (print_symbol_bcache_statistics): Iterate over all
	symbol spaces.
	(print_objfile_statistics): Ditto.
	(maintenance_print_msymbols): Ditto.
	(maintenance_print_objfiles): Ditto.
	(maintenance_info_symtabs): Ditto.
	(maintenance_info_psymtabs): Ditto.
	* symtab.h (SYMTAB_SSPACE): New.
	(struct symtab_and_line) <sspace>: New field.
	* symtab.c (init_sal): Clear the sal's symbol space.
	(find_pc_sect_symtab): Set the sal's symbol space.  Switch thread
	and space.
	(append_expanded_sal): Add symbol space argument.  Iterate over
	all symbol spaces.
	(expand_line_sal): Iterate over all symbol spaces.  Switch symbol
	space.

	* target.h (enum target_waitkind) <TARGET_WAITKIND_VFORK_DONE>: New.
	(struct target_ops) <to_thread_address_space>: New field.
	(target_thread_address_space): Define.
	* target.c (target_detach): Only remove breakpoints from the
	inferior we're detaching.
	(target_thread_address_space): New.

	* top.c (any_thread_of): Delete.
	(kill_or_detach): Use any_thread_of_process.

	* solist.h (struct so_list) <sspace>: New field.
	* solib.h (solib_name_from_address): Adjust prototype.
	* solib.c (so_list_head): Replace with a macro referencing the
	symbol space.
	(update_solib_list): Set the so's symbol space.
	(solib_name_from_address): Add a symbol space argument and adjust.

	* solib-svr4.c (struct svr4_info) <pid>: Delete field.
	<interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low>
	<interp_plt_sect_high>: New fields.
	(svr4_info_p): Delete.
	(svr4_info): Delete.
	(solib_svr4_sspace_data): New.
	(get_svr4_info): Rewrite.
	(svr4_sspace_data_cleanup): New.
	(open_symbol_file_object): Adjust.
	(svr4_default_sos): Adjust.
	(svr4_fetch_objfile_link_map): Adjust.
	(interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low)
	(interp_plt_sect_high): Delete.
	(svr4_in_dynsym_resolve_code): Adjust.
	(enable_break): Adjust.
	(svr4_clear_solib): Revert bit that removed the svr4_info here.
	(_initialize_svr4_solib): Register solib_svr4_sspace_data.  Don't
	install an inferior_exit observer anymore.

	* printcmd.c (struct display) <sspace>: New field.
	(display_command): Set the display's sspace.
	(do_one_display): Match the display's sspace.
	(display_uses_solib_p): Ditto.

	* linux-fork.c: Include gdbthread.h.
	(detach_fork): Moved to infrun.c.
	(_initialize_linux_fork): Moved "detach-on-fork" command to
	infrun.c.
	* infrun.c (detach_fork): Moved from linux-fork.c.
	(proceed_after_vfork_done): New.
	(handle_vfork_child_exec_or_exit): New.
	(follow_exec_mode_replace, follow_exec_mode_keep)
	(follow_exec_mode_names, follow_exec_mode_string)
	(show_follow_exec_mode_string): New.
	(follow_exec): New.  Reinstate the mark_breakpoints_out call.
	Remove shared libraries before attaching new executable.  If user
	wants to keep the symbol space, keep it.
	(displaced_step_fixup): Adjust to pass an address space to the
	breakpoints module.
	(resume): Ditto.
	(clear_proceed_status): In all-stop mode, always clear the proceed
	status of all threads.
	(prepare_to_proceed): Adjust to pass an address space to the
	breakpoints module.
	(proceed): Ditto.
	(adjust_pc_after_break): Ditto.
	(handle_inferior_event): When handling a process exit, switch the
	symbol space to the inferior's that had exited.  Call
	handle_vfork_child_exec_or_exit.  Adjust to pass an address space
	to the breakpoints module.  In non-stop mode, when following a
	fork, also resume the other branch.  Handle
	TARGET_WAITKIND_VFORK_DONE.  Set the symbol space in sals.
	(normal_stop): Prune symbol spaces.
	(_initialize_infrun): Install the new "follow-exec-mode" command.
	"detach-on-fork" moved here.

	* regcache.h (get_regcache_aspace): Declare.
	* regcache.c (struct regcache) <aspace>: New field.
	(regcache_xmalloc): Clear the aspace.
	(get_regcache_aspace): New.
	(regcache_cpy): Copy the aspace field.
	(regcache_cpy_no_passthrough): Ditto.
	(get_thread_regcache): Fetch the thread's address space from the
	target, and store it in the regcache.

	* infcall.c (call_function_by_hand): Set the sal's sspace.

	* arch-utils.c (default_has_shared_address_space): New.
	* arch-utils.h (default_has_shared_address_space): Declare.

	* gdbarch.sh (has_shared_address_space): New.
	* gdbarch.h, gdbarch.c: Regenerate.

	* linux-tdep.c: Include auxv.h, target.h, elf/common.h.
	(linux_has_shared_address_space): New.

	* arm-tdep.c (arm_software_single_step): Pass the frame's address
	space to insert_single_step_breakpoint.
	* arm-linux-tdep.c (arm_linux_software_single_step): Pass the
	frame's sspace to breakpoint functions.
	* cris-tdep.c (crisv32_single_step_through_delay): Ditto.
	(cris_software_single_step): Ditto.
	* mips-tdep.c (deal_with_atomic_sequence): Add frame argument.
	Pass the frame's sspace to breakpoint functions.
	(mips_software_single_step): Adjust.
	(mips_single_step_through_delay): Adjust.
	* rs6000-aix-tdep.c (rs6000_software_single_step): Adjust.
	* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Adjust.
	* solib-irix.c (enable_break): Adjust to pass the current frame's
	address space to breakpoint functions.
	* sparc-tdep.c (sparc_software_single_step): Ditto.
	* spu-tdep.c (spu_software_single_step): Ditto.
	* alpha-tdep.c (alpha_software_single_step): Ditto.
	* record.c (record_wait): Adjust to pass an address space to the
	breakpoints module.

	* fork-child.c (fork_inferior): Set the new inferior's symbol and
	address spaces.
	* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's symbol
	and address spaces.
	(inf_ptrace_attach): Set the inferior's symbol and address spaces.
	* linux-nat.c: Include "solib.h".
	(linux_child_follow_fork): Manage parent and child's symbol and
	address spaces.  Clone the parent's ssymbol space is necessary.
	Don't wait for the vfork to be done here.
	(resume_callback): Don't resume a vfork parent.
	(linux_nat_resume): Also check for pending events in the
	lp->waitstatus field.
	(linux_handle_extended_wait): Report TARGET_WAITKIND_VFORK_DONE
	events to the core.
	(stop_wait_callback): Don't wait for SIGSTOP on vfork parents.
	(cancel_breakpoint): Adjust.
	* linux-thread-db.c (thread_db_wait): Don't remove thread event
	breakpoints here.
	(thread_db_mourn_inferior): Don't mark breakpoints out here.
	Remove thread event breakpoints after mourning.
	* corelow.c (core_open): Set the inferior's symbol and address
	spaces.
	* remote.c (remote_add_inferior): Set the new inferior's symbol
	and address spaces.
	(remote_start_remote): Update address spaces.
	(extended_remote_create_inferior_1): Don't init the thread list if
	we already debugging other inferiors.
	* darwin-nat.c (darwin_attach): Set the new inferior's symbol and
	address spaces.
	* gnu-nat.c (gnu_attach): Ditto.
	* go32-nat.c (go32_create_inferior): Ditto.
	* inf-ttrace.c (inf_ttrace_follow_fork, inf_ttrace_attach): Ditto.
	* monitor.c (monitor_open): Ditto.
	* nto-procfs.c (procfs_attach, procfs_create_inferior): Ditto.
	* procfs.c (do_attach): Ditto.
	* windows-nat.c (do_initial_windows_stuff): Ditto.

	* tui/tui-disasm.c: Include "symspace.h".
	(tui_set_disassem_content): Pass an address space to
	breakpoint_here_p.

gdb/testsuite/
2009-06-29  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	* gdb.base/foll-vfork.exp: Adjust to spell out "follow-fork".
	* gdb.base/foll-exec.exp: Adjust to expect a process id before
	"Executing new program".
	* gdb.base/foll-fork.exp: Adjust to spell out "follow-fork".
	* gdb.base/multi-forks.exp: Ditto.
	* gdb.base/maint.exp: Adjust test.

	* Makefile.in (ALL_SUBDIRS): Add gdb.multi.
	* gdb.multi/Makefile.in: New.
	* gdb.multi/base.exp: New.
	* gdb.multi/goodbye.c: New.
	* gdb.multi/hangout.c: New.
	* gdb.multi/hello.c: New.
	* gdb.multi/bkpt-multi-exec.c: New.
	* gdb.multi/bkpt-multi-exec.exp: New.
	* gdb.multi/crashme.c: New.

gdb/doc/
2009-06-29  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	* gdb.texinfo (Multiple Programs): New node.
	(Process): Rename node to...
	(Forks): ... this.

---
 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                            |  568 ++++++++++++++---
 gdb/breakpoint.h                            |   44 +
 gdb/corelow.c                               |    6 
 gdb/cris-tdep.c                             |    7 
 gdb/darwin-nat.c                            |    2 
 gdb/doc/gdb.texinfo                         |  103 +++
 gdb/exec.c                                  |   70 +-
 gdb/exec.h                                  |    5 
 gdb/fork-child.c                            |    6 
 gdb/frame.c                                 |   46 +
 gdb/frame.h                                 |    9 
 gdb/gdbarch.c                               |   24 
 gdb/gdbarch.h                               |    6 
 gdb/gdbarch.sh                              |    3 
 gdb/gdbcore.h                               |    7 
 gdb/gdbthread.h                             |    4 
 gdb/gnu-nat.c                               |    2 
 gdb/go32-nat.c                              |    5 
 gdb/inf-ptrace.c                            |    4 
 gdb/inf-ttrace.c                            |    4 
 gdb/infcall.c                               |    1 
 gdb/inferior.c                              |   66 +-
 gdb/inferior.h                              |   43 +
 gdb/infrun.c                                |  384 +++++++++++-
 gdb/linespec.c                              |    4 
 gdb/linux-fork.c                            |   12 
 gdb/linux-nat.c                             |  290 ++++++---
 gdb/linux-tdep.c                            |   18 
 gdb/linux-thread-db.c                       |   18 
 gdb/mips-tdep.c                             |   12 
 gdb/monitor.c                               |    4 
 gdb/nto-procfs.c                            |    4 
 gdb/objfiles.c                              |    4 
 gdb/objfiles.h                              |   69 +-
 gdb/printcmd.c                              |   26 
 gdb/procfs.c                                |    2 
 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                            |  142 +---
 gdb/solib.c                                 |   12 
 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                               |   32 -
 gdb/symspace.c                              |  890 ++++++++++++++++++++++++++++
 gdb/symspace.h                              |  278 ++++++++
 gdb/symtab.c                                |   64 +-
 gdb/symtab.h                                |    5 
 gdb/target.c                                |   23 
 gdb/target.h                                |   13 
 gdb/testsuite/Makefile.in                   |    2 
 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/testsuite/gdb.multi/Makefile.in         |   14 
 gdb/testsuite/gdb.multi/base.exp            |  102 +++
 gdb/testsuite/gdb.multi/bkpt-multi-exec.c   |   13 
 gdb/testsuite/gdb.multi/bkpt-multi-exec.exp |   84 ++
 gdb/testsuite/gdb.multi/crashme.c           |   12 
 gdb/testsuite/gdb.multi/goodbye.c           |   62 +
 gdb/testsuite/gdb.multi/hangout.c           |   26 
 gdb/testsuite/gdb.multi/hello.c             |   46 +
 gdb/thread.c                                |   27 
 gdb/top.c                                   |   16 
 gdb/tui/tui-disasm.c                        |    4 
 gdb/windows-nat.c                           |    2 
 83 files changed, 3482 insertions(+), 596 deletions(-)

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2009-07-01 19:16:33.000000000 +0100
+++ src/gdb/Makefile.in	2009-07-01 19:17:15.000000000 +0100
@@ -664,7 +664,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 \
@@ -782,7 +782,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.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.h	2009-07-01 19:17:15.000000000 +0100
@@ -0,0 +1,278 @@
+/* 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;
+struct symbol_space_data;
+
+/* 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 main executable loaded into this symbol space.  This is
+       managed by the exec target.  */
+
+    /* The BFD handle for the main 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_object_file;
+
+    /* 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;
+
+    /* Per sspace data-pointers required by other GDB modules.  */
+    void **data;
+    unsigned num_data;
+  };
+
+/* 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_object_file
+
+/* 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);
+
+/* 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 so that it may be restored by a later
+   call to do_cleanups.  Returns the struct cleanup pointer needed for
+   later doing the cleanup.  */
+extern struct cleanup *save_current_symbol_space (void);
+
+/* Sets SSPACE as the current symbol space.  This is usually used
+   instead of set_current_space_and_thread when the current
+   thread/inferior is not important for the operations that follow.
+   E.g., when accessing the raw symbol tables.  If memory access is
+   required, then you should use switch_to_symbol_space_and_thread.
+   Otherwise, it is the caller's 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);
+
+/* Prune away automatically added symbol spaces that aren't required
+   anymore.  */
+extern void prune_symbol_spaces (void);
+
+/* Keep a registry of per-sspace data-pointers required by other GDB
+   modules.  */
+
+extern const struct symbol_space_data *register_symbol_space_data (void);
+extern const struct symbol_space_data *register_symbol_space_data_with_cleanup
+  (void (*cleanup) (struct symbol_space *, void *));
+extern void clear_symbol_space_data (struct symbol_space *sspace);
+extern void set_symbol_space_data (struct symbol_space *sspace,
+			      const struct symbol_space_data *data, void *value);
+extern void *symbol_space_data (struct symbol_space *sspace,
+			   const struct symbol_space_data *data);
+
+#endif
Index: src/gdb/symspace.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.c	2009-07-01 19:17:15.000000000 +0100
@@ -0,0 +1,890 @@
+/* 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;
+
+/* Prototypes for local functions */
+
+static void symbol_space_alloc_data (struct symbol_space *);
+static void symbol_space_free_data (struct symbol_space *);
+
+
+/* An address space.  Currently this is not used for much other than
+   for comparing if sspaces/inferior/threads see the same address
+   space.  */
+
+struct address_space
+{
+  int num;
+};
+
+/* Create a new address space object, and add it to the list.  */
+
+struct address_space *
+new_address_space (void)
+{
+  struct address_space *aspace;
+
+  aspace = XZALLOC (struct address_space);
+  aspace->num = ++highest_address_space_num;
+
+  return aspace;
+}
+
+/* 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 on this target system.  */
+
+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 ();
+}
+
+static void
+free_address_space (struct address_space *aspace)
+{
+  xfree (aspace);
+}
+
+/* Start counting over from scratch.  */
+
+static void
+init_address_spaces (void)
+{
+  highest_address_space_num = 0;
+}
+
+
+
+/* Add a new empty symbol space to the symbol space list, and binds it
+   to ASPACE.  Returns the pointer to the new object.  */
+
+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->aspace = aspace;
+
+  symbol_space_alloc_data (sspace);
+
+  sspace->next = symbol_spaces;
+  symbol_spaces = sspace;
+
+  return sspace;
+}
+
+/* Releases symbol space SSPACE, and all its contents (shared
+   libraries, objfiles, and any other references to the sspace in
+   other modules).  It is an internal error to call this when SSPACE
+   is the current symbol space, since there should always be a symbol
+   space.  */
+
+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));
+    /* Discard any data modules have associated with the sspace.  */
+  symbol_space_free_data (sspace);
+  xfree (sspace);
+
+  do_cleanups (old_chain);
+}
+
+/* Unlinks SSPACE from the sspace list, and releases it.  */
+
+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;
+    }
+}
+
+/* Copies symbol space SRC to DEST.  Copies the main executable file,
+   and the main symbol file.  Returns DEST.  */
+
+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 != NULL)
+    exec_file_attach (bfd_get_filename (src->ebfd), 0);
+
+  if (src->symfile_object_file != NULL)
+    symbol_file_add_main (src->symfile_object_file->name, 0);
+
+  do_cleanups (old_chain);
+  return dest;
+}
+
+/* Sets SSPACE as the current symbol space.  It is the caller's
+   responsibility to make sure that the currently selected
+   inferior/thread matches the selected symbol space.  */
+
+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 ();
+}
+
+/* A cleanups callback, helper for save_current_symbol_space
+   below.  */
+
+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;
+}
+
+/* Find symbol space number NUM; returns NULL if not found.  */
+
+static 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;
+}
+
+/* Implementation of the "symbol-space SSPACE" command (aliased
+   "sspace").  Switching to a symbol space implicitly switches to the
+   first thread/inferior that is bound to it, unless there's none.  */
+
+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);
+    }
+}
+
+/* add-symbol-space [-copies N] [-exec FILENAME]  */
+
+void
+add_symbol_space_command (char *args, int from_tty)
+{
+  int i, copies = 1;
+  char *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, "-exec") == 0)
+		{
+		  ++argv;
+		  if (!*argv)
+		    error ("No argument to -exec");
+		  exec = *argv;
+		}
+	    }
+	  else
+	    error (_("Invalid argument"));
+	}
+    }
+
+  save_current_space_and_thread ();
+
+  for (i = 0; i < copies; ++i)
+    {
+      struct address_space *aspace;
+      struct symbol_space *sspace;
+
+      /* If all inferiors share an address space on this system, this
+	 doesn't really return a new address space; otherwise, it
+	 really does.  */
+      aspace = maybe_new_address_space ();
+      sspace = add_symbol_space (aspace);
+
+      printf_filtered ("Added symbol space %d\n", sspace->num);
+
+      if (exec != NULL)
+	{
+	  /* Switch over temporarily, while reading executable and
+	     symbols.q  */
+	  set_current_symbol_space (sspace);
+	  switch_to_thread (null_ptid);
+
+	  exec_file_attach (exec, from_tty);
+	  symbol_file_add_main (exec, from_tty);
+	}
+    }
+
+  do_cleanups (old_chain);
+
+  printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+/* clone-symbol-space [-copies N] [ID] */
+
+void
+clone_symbol_space_command (char *args, int from_tty)
+{
+  int i, copies = 1;
+  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 (orgspace == NULL)
+		{
+		  int num;
+
+		  /* The first non-option (-) argument specified the
+		     symbol space ID.  */
+		  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 no symbol space id was specified, then the user wants to clone
+     the current symbol space.  */
+  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;
+
+      /* If all inferiors share an address space on this system, this
+	 doesn't really return a new address space; otherwise, it
+	 really does.  */
+      aspace = maybe_new_address_space ();
+      sspace = add_symbol_space (aspace);
+
+      printf_filtered ("Added symbol space %d.\n", sspace->num);
+
+      switch_to_thread (null_ptid);
+      clone_symbol_space (sspace, orgspace);
+    }
+
+  do_cleanups (old_chain);
+
+  printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+/* remove-symbol-space ID */
+
+void
+remove_symbol_space_command (char *args, int from_tty)
+{
+  int num;
+  struct symbol_space *sspace;
+  struct inferior *inf;
+
+  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 not remove current symbol space."));
+
+  /* Can't remove a symbol space if inferiors are still bound to
+     it.  */
+  inf = find_inferior_for_symbol_space (sspace);
+  if (inf != NULL)
+    error (_("Can not remove symbol space with bound inferiors."));
+
+  remove_symbol_space (sspace);
+}
+
+/* Returns true iff there's no inferior bound to 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;
+}
+
+/* Prune away automatically added symbol spaces that aren't required
+   anymore.  */
+
+void
+prune_symbol_spaces (void)
+{
+  struct symbol_space *ss, **ss_link;
+  struct symbol_space *current = current_symbol_space;
+
+  ss = symbol_spaces;
+  ss_link = &symbol_spaces;
+  while (ss)
+    {
+      if (ss == current
+	  || !ss->removable
+	  || !sspace_empty_p (ss))
+	{
+	  ss_link = &ss->next;
+	  ss = *ss_link;
+	  continue;
+	}
+
+      *ss_link = ss->next;
+      release_symbol_space (ss);
+      ss = *ss_link;
+    }
+}
+
+/* Prints the list of symbol spaces and their details on UIOUT.  If
+   REQUESTED is not -1, it's the ID of the sspace that should be
+   printed.  Otherwise, all spaces are printed.  */
+
+static void
+print_symbol_space (struct ui_out *uiout, int requested)
+{
+  struct symbol_space *sspace;
+  int count = 0;
+  struct cleanup *old_chain;
+
+  /* Might as well prune away unneeded ones, so the user doesn't even
+     seem them.  */
+  prune_symbol_spaces ();
+
+  /* Compute number of sspaces we will print.  */
+  ALL_SSPACES (sspace)
+    {
+      if (requested != -1 && sspace->num != requested)
+	continue;
+
+      ++count;
+    }
+
+  /* There should always be at least one.  */
+  gdb_assert (count > 0);
+
+  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;
+
+      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");
+
+      /* Print extra info that doesn't really fit in tabular form.
+	 Currently, we print the list of inferiors bound to a sspace.
+	 There can be more than one inferior bound to the same sspace,
+	 e.g., both parent/child inferiors in a vfork, or, on targets
+	 that share sspaces between inferiors.  */
+      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);
+}
+
+/* Boolean test for an already-known symbol space id.  */
+
+static int
+valid_symbol_space_id (int num)
+{
+  struct symbol_space *sspace;
+
+  ALL_SSPACES (sspace)
+    if (sspace->num == num)
+      return 1;
+
+  return 0;
+}
+
+/* If ARGS is NULL or empty, print information about all symbol
+   spaces.  Otherwise, ARGS is a text representation of a LONG
+   indicating which the symbol space to print information about.  */
+
+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);
+}
+
+/* Simply returns the count of symbol spaces.  */
+
+int
+number_of_symbol_spaces (void)
+{
+  struct symbol_space *sspace;
+  int count = 0;
+
+  ALL_SSPACES (sspace)
+    count++;
+
+  return count;
+}
+
+/* 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.
+
+   It is assumed that there are no bound inferiors yet, otherwise,
+   they'd be left with stale referenced to released aspaces.  */
+
+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 ();
+    }
+}
+
+/* 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_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;
+}
+
+/* Switches full context to symbol space SSPACE.  Switches to the
+   first thread found bound to SSPACE.  */
+
+void
+switch_to_symbol_space_and_thread (struct symbol_space *sspace)
+{
+  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);
+	  /* Switching thread switches sspace implicitly.  We're
+	     done.  */
+	  return;
+	}
+    }
+
+  switch_to_thread (null_ptid);
+  set_current_symbol_space (sspace);
+}
+
+
+
+/* Keep a registry of per-symbol_space data-pointers required by other GDB
+   modules.  */
+
+struct symbol_space_data
+{
+  unsigned index;
+  void (*cleanup) (struct symbol_space *, void *);
+};
+
+struct symbol_space_data_registration
+{
+  struct symbol_space_data *data;
+  struct symbol_space_data_registration *next;
+};
+
+struct symbol_space_data_registry
+{
+  struct symbol_space_data_registration *registrations;
+  unsigned num_registrations;
+};
+
+static struct symbol_space_data_registry symbol_space_data_registry
+  = { NULL, 0 };
+
+const struct symbol_space_data *
+register_symbol_space_data_with_cleanup
+  (void (*cleanup) (struct symbol_space *, void *))
+{
+  struct symbol_space_data_registration **curr;
+
+  /* Append new registration.  */
+  for (curr = &symbol_space_data_registry.registrations;
+       *curr != NULL; curr = &(*curr)->next);
+
+  *curr = XMALLOC (struct symbol_space_data_registration);
+  (*curr)->next = NULL;
+  (*curr)->data = XMALLOC (struct symbol_space_data);
+  (*curr)->data->index = symbol_space_data_registry.num_registrations++;
+  (*curr)->data->cleanup = cleanup;
+
+  return (*curr)->data;
+}
+
+const struct symbol_space_data *
+register_symbol_space_data (void)
+{
+  return register_symbol_space_data_with_cleanup (NULL);
+}
+
+static void
+symbol_space_alloc_data (struct symbol_space *sspace)
+{
+  gdb_assert (sspace->data == NULL);
+  sspace->num_data = symbol_space_data_registry.num_registrations;
+  sspace->data = XCALLOC (sspace->num_data, void *);
+}
+
+static void
+symbol_space_free_data (struct symbol_space *sspace)
+{
+  gdb_assert (sspace->data != NULL);
+  clear_symbol_space_data (sspace);
+  xfree (sspace->data);
+  sspace->data = NULL;
+}
+
+void
+clear_symbol_space_data (struct symbol_space *sspace)
+{
+  struct symbol_space_data_registration *registration;
+  int i;
+
+  gdb_assert (sspace->data != NULL);
+
+  for (registration = symbol_space_data_registry.registrations, i = 0;
+       i < sspace->num_data;
+       registration = registration->next, i++)
+    if (sspace->data[i] != NULL && registration->data->cleanup)
+      registration->data->cleanup (sspace, sspace->data[i]);
+
+  memset (sspace->data, 0, sspace->num_data * sizeof (void *));
+}
+
+void
+set_symbol_space_data (struct symbol_space *sspace,
+		       const struct symbol_space_data *data,
+		       void *value)
+{
+  gdb_assert (data->index < sspace->num_data);
+  sspace->data[data->index] = value;
+}
+
+void *
+symbol_space_data (struct symbol_space *sspace, const struct symbol_space_data *data)
+{
+  gdb_assert (data->index < sspace->num_data);
+  return sspace->data[data->index];
+}
+
+
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_symspace;
+
+void
+_initialize_symspace (void)
+{
+  add_info ("symbol-spaces", info_symbol_spaces_command, _("\
+Info about currently known symbol spaces."));
+  add_info_alias ("sspaces", "symbol-spaces", 0);
+
+  add_com ("symbol-space", no_class, symbol_space_command, _("\
+Change the current symbol space."));
+  add_com_alias ("sspace", "symbol-space", no_class, 0);
+
+  add_com ("add-symbol-space", no_class, add_symbol_space_command, _("\
+Add a new symbol space.\n\
+Usage: add-symbol-space [-copies <N>] [-exec <FILENAME>]\n\
+N is the optional number of spaces to add, default is 1.\n\
+FILENAME is the file name of the main executable to load\n\
+in the new symbol spaces."));
+
+  add_com ("remove-symbol-space", no_class, remove_symbol_space_command, _("\
+Remove symbol-space ID.\n\
+Usage: remove-symbol-space ID\n\
+Trying to remove the current symbol space, or a symbol space that\n\
+has bound inferiors is an error."));
+
+  add_com ("clone-symbol-space", no_class, clone_symbol_space_command, _("\
+Clone symbol space SPACE.\n\
+Usage: clone-symbol-space [-copies <N>] [ID]\n\
+Add N copies of symbol space ID.  The new symbol space has the same\n\
+executable loaded as the original space.  If -copies is not specified,\n\
+adds 1 copy.  If ID is not specified, it is the current symbol space\n\
+that is cloned."));
+
+  /* There's always one symbol space.  */
+  current_symbol_space = add_symbol_space (new_address_space ());
+}
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/breakpoint.h	2009-07-01 19:17:15.000000000 +0100
@@ -166,6 +166,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
@@ -258,6 +261,14 @@ 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.  */
+  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
@@ -392,6 +403,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.  */
@@ -495,7 +509,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);
 
 /* This bpstat_what stuff tells wait_for_inferior what to do with a
    breakpoint (a challenging task).  */
@@ -679,17 +694,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);
 
@@ -707,7 +722,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);
 
@@ -737,6 +753,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
@@ -772,6 +790,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 (int thread);
 extern void delete_longjmp_breakpoint (int thread);
 
@@ -857,13 +880,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/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2009-07-01 19:15:24.000000000 +0100
+++ src/gdb/breakpoint.c	2009-07-01 19:17:15.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);
 
@@ -396,6 +404,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;
+
 
 /* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
    Advance *PP after the string and any trailing whitespace.
@@ -722,6 +732,10 @@ breakpoint_restore_shadows (gdb_byte *bu
       continue;
     if (!b->inserted)
       continue;
+    if (!breakpoint_address_match (b->target_info.placed_address_space, 0,
+				   current_symbol_space->aspace, 0))
+      continue;
+
     /* Addresses and length of the part of the breakpoint that
        we need to copy.  */
     bp_addr = b->target_info.placed_address;
@@ -876,6 +890,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
@@ -904,6 +919,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;
@@ -1005,6 +1022,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;
@@ -1084,6 +1102,7 @@ insert_bp_location (struct bp_location *
   /* Initialize the target-specific information.  */
   memset (&bpt->target_info, 0, sizeof (bpt->target_info));
   bpt->target_info.placed_address = bpt->address;
+  bpt->target_info.placed_address_space = bpt->sspace->aspace;
 
   if (bpt->loc_type == bp_loc_software_breakpoint
       || bpt->loc_type == bp_loc_hardware_breakpoint)
@@ -1197,7 +1216,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;
@@ -1274,6 +1293,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
@@ -1317,9 +1378,14 @@ 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 thread_info *tp;
+      CORE_ADDR last_addr;
+
       if (!should_be_inserted (b) || b->inserted)
 	continue;
 
@@ -1329,6 +1395,35 @@ 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;
+
+      if (!ptid_equal (inferior_ptid, null_ptid))
+	{
+	  struct inferior *inf = current_inferior ();
+	  if (inf->waiting_for_vfork_done)
+	    {
+	      /* This is set when we're attached to the parent of the
+		 vfork, and have detached from the child.  The child
+		 is running free, and we expect it to do an exec or
+		 exit, at which point the OS makes the parent
+		 schedulable again (and the target reports that the
+		 vfork is done).  Until the child is done with the
+		 shared memory region, do not insert breakpoints in
+		 parent, otherwise the child could still trip on the
+		 parent's breakpoints.  Since the parent is blocked
+		 anyway, it won't miss any breakpoint.  */
+	      continue;
+	    }
+	}
+
       val = insert_bp_location (b, tmp_error_stream,
 				    &disabled_breaks,
 				    &hw_breakpoint_error);
@@ -1407,6 +1502,30 @@ remove_breakpoints (void)
   return 0;
 }
 
+/* Remove breakpoints of process PID.  */
+
+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)
 {
@@ -1428,17 +1547,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;
@@ -1467,6 +1599,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--;
@@ -1510,8 +1643,13 @@ create_overlay_event_breakpoint (char *f
 static void
 create_longjmp_master_breakpoint (char *func_name)
 {
+  struct symbol_space *sspace;
   struct objfile *objfile;
+  struct cleanup *old_chain;
+
+  old_chain = save_current_symbol_space ();
 
+  ALL_SSPACES (sspace)
   ALL_OBJFILES (objfile)
     {
       struct breakpoint *b;
@@ -1520,6 +1658,8 @@ create_longjmp_master_breakpoint (char *
       if (!gdbarch_get_longjmp_target_p (get_objfile_arch (objfile)))
 	continue;
 
+      set_current_symbol_space (sspace);
+
       m = lookup_minimal_symbol_text (func_name, objfile);
       if (m == NULL)
         continue;
@@ -1530,6 +1670,8 @@ create_longjmp_master_breakpoint (char *
       b->enable_state = bp_disabled;
     }
   update_global_location_list (1);
+
+  do_cleanups (old_chain);
 }
 
 void
@@ -1548,10 +1690,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)
       {
@@ -1646,17 +1792,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);
@@ -1668,10 +1819,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.  */
@@ -1745,7 +1903,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)
@@ -1781,6 +1939,30 @@ 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 ();
+
+  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
@@ -1789,7 +1971,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
@@ -1810,6 +1993,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.  */
@@ -1817,11 +2001,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:
@@ -1864,6 +2054,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
@@ -1875,7 +2070,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;
@@ -1888,7 +2083,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) 
@@ -1907,13 +2103,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;
@@ -1925,7 +2122,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;
 
@@ -1936,7 +2133,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) 
@@ -1953,12 +2151,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;
@@ -1968,7 +2166,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;
@@ -1979,7 +2177,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) 
@@ -1991,7 +2190,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;
@@ -2001,7 +2200,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.  */
@@ -2018,7 +2218,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)
@@ -2877,7 +3078,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;
 
@@ -2888,7 +3090,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) 
@@ -3112,7 +3315,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;
@@ -3140,7 +3344,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 */
@@ -3195,7 +3399,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.  */
@@ -3499,6 +3704,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 
@@ -3534,6 +3744,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. */
@@ -3541,7 +3753,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;
@@ -3718,6 +3930,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)
@@ -3850,9 +4074,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
@@ -3875,7 +4099,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);
 	}
     }
 }
@@ -3896,7 +4120,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;
 	}
     }
@@ -4004,7 +4228,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);
@@ -4054,29 +4278,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)
@@ -4084,7 +4313,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);
@@ -4112,10 +4341,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;
@@ -4149,6 +4380,20 @@ breakpoint_address_is_meaningful (struct
 	  && type != bp_catchpoint);
 }
 
+/* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the
+   same breakpoint location.  In most targets, this is will be true if
+   ASPACE1 matches ASPACE2.  On targets that have global breakpoints,
+   the address space doesn't really matter.  */
+
+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.
@@ -4156,7 +4401,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;
@@ -4167,9 +4414,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)
@@ -4201,10 +4449,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__,
@@ -4226,7 +4475,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
@@ -4427,6 +4676,9 @@ set_raw_breakpoint (struct symtab_and_li
   struct breakpoint *b = set_raw_breakpoint_without_location (bptype);
   CORE_ADDR adjusted_address;
 
+  if (bptype != bp_catchpoint)
+    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
@@ -4438,6 +4690,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;
@@ -4485,7 +4742,8 @@ set_longjmp_breakpoint (int thread)
      longjmp "master" breakpoints.  Here, we simply create momentary
      clones of those and enable them for the requested thread.  */
   ALL_BREAKPOINTS_SAFE (b, temp)
-    if (b->type == bp_longjmp_master)
+    if (b->sspace == current_symbol_space
+	&& b->type == bp_longjmp_master)
       {
 	struct breakpoint *clone = clone_momentary_breakpoint (b);
 	clone->type = bp_longjmp;
@@ -4557,7 +4815,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);
 }
 
@@ -4582,7 +4841,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);
 }
 
@@ -4615,11 +4875,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
 	)
       {
@@ -4650,6 +4911,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))
@@ -4853,6 +5115,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);
@@ -5074,6 +5337,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;
@@ -5083,6 +5347,7 @@ clone_momentary_breakpoint (struct break
   copy->line_number = orig->line_number;
   copy->frame_id = orig->frame_id;
   copy->thread = orig->thread;
+  copy->sspace = orig->sspace;
 
   copy->enable_state = bp_enabled;
   copy->disposition = disp_donttouch;
@@ -5258,6 +5523,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);
@@ -5292,7 +5562,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)
@@ -5337,7 +5610,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)
 	{
@@ -5378,6 +5651,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);
 }
@@ -5396,20 +5671,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)
 {
@@ -5418,6 +5692,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.  */
@@ -5430,9 +5705,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
@@ -5442,6 +5724,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;      
     }
 
@@ -5452,6 +5735,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))
 	    {
@@ -5495,7 +5783,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
@@ -5586,6 +5875,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
@@ -5903,6 +6193,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);
     }
@@ -5969,19 +6260,25 @@ 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;
 
-  if (sym == NULL)
-    return;
+  old_chain = save_current_space_and_thread ();
 
-  start_sal = find_function_start_sal (sym, 1);
-  if (sal->pc < start_sal.pc)
+  sym = find_pc_function (sal->pc);
+  if (sym != NULL)
     {
-      start_sal.explicit_line = sal->explicit_line;
-      start_sal.explicit_pc = sal->explicit_pc;
-      *sal = start_sal;
+      start_sal = find_function_start_sal (sym, 1);
+      if (sal->pc < start_sal.pc)
+	{
+	  start_sal.explicit_line = sal->explicit_line;
+	  start_sal.explicit_pc = sal->explicit_pc;
+	  *sal = start_sal;
+	}
     }
+
+  do_cleanups (old_chain);
 }
 
 /* Helper function for break_command_1 and disassemble_command.  */
@@ -6032,10 +6329,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);
 	    }
 	}
     }
@@ -6225,6 +6527,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;
@@ -6891,7 +7195,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.
@@ -7006,6 +7310,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."));
 
@@ -7069,13 +7374,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)
@@ -7244,8 +7551,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;
@@ -7627,7 +7938,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;
@@ -7664,12 +7976,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)
     {
@@ -7690,6 +8002,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,
@@ -7723,29 +8039,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:
@@ -7817,6 +8135,7 @@ breakpoint_re_set_one (void *bint)
       break;
     }
 
+  do_cleanups (cleanups);
   return 0;
 }
 
@@ -7827,9 +8146,12 @@ breakpoint_re_set (void)
   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 */
@@ -7842,6 +8164,8 @@ breakpoint_re_set (void)
   set_language (save_language);
   input_radix = save_input_radix;
 
+  do_cleanups (old_chain);
+
   create_overlay_event_breakpoint ("_ovly_debug_event");
   create_longjmp_master_breakpoint ("longjmp");
   create_longjmp_master_breakpoint ("_longjmp");
@@ -7860,6 +8184,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;
     }
 }
 
@@ -8230,14 +8560,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.  */
@@ -8269,7 +8600,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;
 
@@ -8288,7 +8619,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));
@@ -8316,14 +8647,17 @@ 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
+	  && breakpoint_address_match (bp_tgt->placed_address_space,
+				       bp_tgt->placed_address,
+				       aspace, pc))
 	return 1;
     }
 
Index: src/gdb/exec.h
===================================================================
--- src.orig/gdb/exec.h	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/exec.h	2009-07-01 19:17:15.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.  */
 
@@ -82,5 +86,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/exec.c
===================================================================
--- src.orig/gdb/exec.c	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/exec.c	2009-07-01 19:17:15.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
@@ -295,7 +302,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 +473,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 +510,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/gdbcore.h
===================================================================
--- src.orig/gdb/gdbcore.h	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/gdbcore.h	2009-07-01 19:17:15.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.  */
 
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/frame.h	2009-07-01 19:17:15.000000000 +0100
@@ -398,6 +398,15 @@ extern int frame_relative_level (struct 
 
 extern enum frame_type get_frame_type (struct frame_info *);
 
+/* Return the frame's symbol space.  */
+extern struct symbol_space *get_frame_symbol_space (struct frame_info *);
+
+/* Unwind THIS frame's symbol space from the NEXT frame.  */
+extern struct symbol_space *frame_unwind_symbol_space (struct frame_info *);
+
+/* Return the frame's address space.  */
+extern struct address_space *get_frame_address_space (struct frame_info *);
+
 /* For frames where we can not unwind further, describe why.  */
 
 enum unwind_stop_reason
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2009-07-01 19:15:25.000000000 +0100
+++ src/gdb/frame.c	2009-07-01 19:17:15.000000000 +0100
@@ -70,6 +70,12 @@ struct frame_info
      moment leave this as speculation.  */
   int level;
 
+  /* The frame's symbol space.  */
+  struct symbol_space *sspace;
+
+  /* The frame's address space.  */
+  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
@@ -981,10 +987,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.  */
@@ -1066,7 +1074,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)
 	{
@@ -1197,7 +1205,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
@@ -1206,6 +1214,10 @@ create_new_frame (CORE_ADDR addr, CORE_A
   fi->next->prev_pc.value = pc;
   fi->next->prev_pc.p = 1;
 
+  /* We currently assume that frame chain's can't cross spaces.  */
+  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);
@@ -1478,6 +1490,11 @@ get_prev_frame_raw (struct frame_info *t
   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.  */
@@ -1849,6 +1866,29 @@ 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);
+
+  /* This is really a placeholder to keep the API consistent --- we
+     assume for now that we don't have frame chains crossing
+     spaces.  */
+  return this_frame->sspace;
+}
+
+struct address_space *
+get_frame_address_space (struct frame_info *frame)
+{
+  return frame->aspace;
+}
+
 /* Memory access methods.  */
 
 void


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]