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]

[v4 1/2] multi-executable support


2009-09-03  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	Add multi-executable/process support to GDB.

	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 (executing_startup): Delete.
	(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.  Don't insert breakpoints in a vfork
	parent waiting for vfork done if we're not attached to the vfork
	child.
	(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.
	(disable_breakpoints_before_startup): Skip breakpoints from other
	symbol spaces.  Set executing_startup in the current symbol space.
	(enable_breakpoints_after_startup): Clear executing_startup in the
	current symbol space.  Skip breakpoints from other symbol spaces.
	(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): Add symbol space and executable columns.  Print
	vfork parent/child relationships.
	* objfiles.h: Include "symspace.h".
	(struct objfile) <sspace>: New field.
	(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, symfile_objfile): Delete.
	(struct objfile_sspace_info): New.
	(objfiles_sspace_data): New.
	(objfiles_sspace_data_cleanup): New.
	(get_objfile_sspace_data): New.
	(objfiles_changed_p): Delete.
	(allocate_objfile): Set the objfile's symbol space.  Adjust to
	reference objfiles_changed_p in sspace data.
	(free_objfile): Adjust to reference objfiles_changed_p in sspace
	data.
	(objfile_relocate): Ditto.
	(update_section_map): Add sspace argument.  Adjust to iterate over
	objfiles in the passed in sspace.
	(find_pc_section): Delete sections and num_sections statics.
	Adjust to refer to symbol space's objfiles_changed_p.  Adjust to
	refer to sections and num_sections store in the objfile's sspace
	data.
	(objfiles_changed): Adjust to reference objfiles_changed_p in
	sspace data.
	(_initialize_objfiles): New.
	* 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.

	* defs.h (initialize_symspace): Declare.
	* top.c (gdb_init): Call it.

	* solist.h (struct so_list) <sspace>: New field.
	* solib.h (struct symbol_space): Forward declare.
	(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, 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,
	and reinstate clearing debug_base, debug_loader_offset_p,
	debug_loader_offset and debug_loader_name.
	(_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 (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 and detach-fork is off, 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.
	(_initialize_linux_tdep): Declare.

	* 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.  Refuse to resume if
	following the vfork parent while leaving the child stopped.
	(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: Include symspace.h.
	(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.

	* NEWS: Mention multi-program, or multi-exec debugging support.
	Mention new commands "info symbol-spaces", "symbol-space",
	"add-symbol-space", "clone-symbol-space", "remove-symbol-space",
	and new option "set follow-exec-mode".

2009-09-03  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	gdb/testsuite/
	* 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/attach.exp: Adjust to spell out "symbol-file".
	* 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.

2009-09-03  Pedro Alves  <pedro@codesourcery.com>
	    Stan Shebs  <stan@codesourcery.com>

	gdb/doc/
	* gdb.texinfo (Multiple Programs): New node.
	(Process): Rename node to...
	(Forks): ... this.  Document "set|show follow-exec-mode".  Add
	"info inferiors" example showing vfork parent/child relationships.
	(Inferiors) <info inferiors>: Mention the new 'SSpace' and 'Main
	Program' columns.  Update example.  Mention possible extra output
	below each inferior line.

---
 gdb/Makefile.in                             |    4 
 gdb/NEWS                                    |   41 +
 gdb/alpha-tdep.c                            |    3 
 gdb/arch-utils.c                            |    8 
 gdb/arch-utils.h                            |    2 
 gdb/arm-linux-tdep.c                        |    3 
 gdb/arm-tdep.c                              |    3 
 gdb/breakpoint.c                            |  589 ++++++++++++++----
 gdb/breakpoint.h                            |   45 +
 gdb/corelow.c                               |    6 
 gdb/cris-tdep.c                             |    8 
 gdb/darwin-nat.c                            |    2 
 gdb/defs.h                                  |    4 
 gdb/doc/gdb.texinfo                         |  267 ++++++++
 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                              |   54 +
 gdb/inferior.h                              |   43 +
 gdb/infrun.c                                |  384 +++++++++++-
 gdb/linespec.c                              |    4 
 gdb/linux-fork.c                            |   11 
 gdb/linux-nat.c                             |  291 ++++++---
 gdb/linux-tdep.c                            |   22 
 gdb/linux-thread-db.c                       |   18 
 gdb/mips-tdep.c                             |   12 
 gdb/monitor.c                               |    5 
 gdb/nto-procfs.c                            |    4 
 gdb/objfiles.c                              |  123 ++-
 gdb/objfiles.h                              |   67 +-
 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                            |    6 
 gdb/solib-svr4.c                            |  155 ++--
 gdb/solib.c                                 |   12 
 gdb/solib.h                                 |    3 
 gdb/solist.h                                |    3 
 gdb/source.c                                |   30 
 gdb/sparc-tdep.c                            |    5 
 gdb/spu-tdep.c                              |    6 
 gdb/stack.c                                 |    6 
 gdb/symfile.c                               |    2 
 gdb/symmisc.c                               |   32 -
 gdb/symspace.c                              |  892 ++++++++++++++++++++++++++++
 gdb/symspace.h                              |  288 +++++++++
 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/attach.exp           |    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                                   |    6 
 gdb/tui/tui-disasm.c                        |    4 
 gdb/windows-nat.c                           |    2 
 86 files changed, 3803 insertions(+), 635 deletions(-)

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/Makefile.in	2009-09-03 03:02:39.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 \
@@ -783,7 +783,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-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,288 @@
+/* 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;
+
+    /* True if this symbol space's section offsets don't yet represent
+       the final offsets of the "live" address space (that is, the
+       section addresses still require the relocation offsets to be
+       applied, and hence we can't trust the section addresses for
+       anything that pokes at live memory).  E.g., for qOffsets
+       targets, or for PIE executables, until we connect and ask the
+       target for the final relocation offsets, the symbols we've used
+       to set breakpoints point at the wrong addresses.  */
+    int executing_startup;
+
+    /* 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-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,892 @@
+/* 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];
+}
+
+
+
+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.  Note that this function isn't
+     an automatic _initialize_foo function, since other
+     _initialize_foo routine may need to install their per-sspace data
+     keys.  We can only allocate a symspace when all those modules
+     have done that.  Do this before initialize_current_architecture,
+     because that accesses exec_bfd.  */
+  current_symbol_space = add_symbol_space (new_address_space ());
+}
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/breakpoint.h	2009-09-03 03:02:39.000000000 +0100
@@ -175,6 +175,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
@@ -271,6 +274,14 @@ struct bp_location
      different from the breakpoint architecture.  */
   struct gdbarch *gdbarch;
 
+  /* 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
@@ -405,6 +416,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;
     /* Architecture we used to set the breakpoint.  */
@@ -510,7 +524,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).  */
@@ -697,17 +712,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);
 
@@ -725,7 +740,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);
 
@@ -756,6 +772,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
@@ -791,6 +809,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);
 
@@ -899,13 +922,15 @@ 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 (struct gdbarch *, CORE_ADDR);
+extern void insert_single_step_breakpoint (struct gdbarch *,
+					   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 (struct gdbarch *, CORE_ADDR);
+extern void *deprecated_insert_raw_breakpoint (struct gdbarch *,
+					       struct address_space *, CORE_ADDR);
 extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
 
 /* Check if any hardware watchpoints have triggered, according to the
Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/breakpoint.c	2009-09-03 03:02:39.000000000 +0100
@@ -119,9 +119,15 @@ static CORE_ADDR adjust_breakpoint_addre
 					    CORE_ADDR bpaddr,
                                             enum bptype bptype);
 
-static void describe_other_breakpoints (struct gdbarch *, CORE_ADDR,
+static void describe_other_breakpoints (struct gdbarch *,
+					struct symbol_space *, 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 breakpoints_info (char *, int);
 
 static void breakpoint_1 (int, int);
@@ -148,6 +154,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);
 
@@ -190,7 +197,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);
 
@@ -320,9 +328,6 @@ static int executing_breakpoint_commands
 /* Are overlay event breakpoints enabled? */
 static int overlay_events_enabled;
 
-/* Are we executing startup code?  */
-static int executing_startup;
-
 /* Walk the following statement or block through all breakpoints.
    ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
    breakpoint.  */
@@ -406,6 +411,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.
@@ -754,6 +761,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;
@@ -908,6 +919,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
@@ -936,6 +948,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;
@@ -1038,6 +1052,8 @@ update_watchpoint (struct breakpoint *b,
 		    ;
 		  *tmp = loc;
 		  loc->gdbarch = get_type_arch (value_type (v));
+
+		  loc->sspace = frame_sspace;
 		  loc->address = addr;
 		  loc->length = len;
 		  loc->watchpoint_type = type;
@@ -1117,6 +1133,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)
@@ -1235,7 +1252,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;
@@ -1313,6 +1330,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
@@ -1356,9 +1415,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;
 
@@ -1368,6 +1432,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);
@@ -1442,6 +1535,30 @@ remove_breakpoints (void)
   return val;
 }
 
+/* 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)
 {
@@ -1459,17 +1576,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;
@@ -1499,6 +1629,7 @@ create_internal_breakpoint (struct gdbar
 
   sal.pc = address;
   sal.section = find_pc_overlay (sal.pc);
+  sal.sspace = current_symbol_space;
 
   b = set_raw_breakpoint (gdbarch, sal, type);
   b->number = internal_breakpoint_number--;
@@ -1543,8 +1674,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;
@@ -1553,6 +1689,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;
@@ -1564,6 +1702,8 @@ create_longjmp_master_breakpoint (char *
       b->enable_state = bp_disabled;
     }
   update_global_location_list (1);
+
+  do_cleanups (old_chain);
 }
 
 void
@@ -1582,10 +1722,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)
       {
@@ -1687,25 +1831,36 @@ detach_breakpoints (int pid)
   struct bp_location *b;
   int val = 0;
   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);
   }
   do_cleanups (old_chain);
   return val;
 }
 
+/* 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.  */
@@ -1783,7 +1938,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)
@@ -1819,6 +1974,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
@@ -1827,7 +2006,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
@@ -1848,6 +2028,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.  */
@@ -1855,11 +2036,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:
@@ -1902,6 +2089,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
@@ -1913,7 +2105,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;
@@ -1926,7 +2118,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) 
@@ -1945,13 +2138,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;
@@ -1963,7 +2157,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;
 
@@ -1974,7 +2168,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) 
@@ -1991,12 +2186,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;
@@ -2006,7 +2201,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;
@@ -2017,7 +2212,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) 
@@ -2029,7 +2225,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;
@@ -2039,7 +2235,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.  */
@@ -2056,7 +2253,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)
@@ -2916,7 +3114,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;
 
@@ -2927,7 +3126,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) 
@@ -3151,7 +3351,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;
@@ -3179,7 +3380,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 */
@@ -3234,7 +3435,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.  */
@@ -3537,6 +3739,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 
@@ -3572,6 +3779,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. */
@@ -3580,7 +3789,8 @@ print_one_breakpoint_location (struct br
 			       struct bp_location *loc,
 			       int loc_number,
 			       struct bp_location **last_loc,
-			       int print_address_bits)
+			       int print_address_bits,
+			       int allflag)
 {
   struct command_line *l;
   struct symbol *sym;
@@ -3760,6 +3970,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)
@@ -3893,9 +4115,10 @@ print_one_breakpoint_location (struct br
 
 static void
 print_one_breakpoint (struct breakpoint *b,
-		      struct bp_location **last_loc, int print_address_bits)
+		      struct bp_location **last_loc, int print_address_bits,
+		      int allflag)
 {
-  print_one_breakpoint_location (b, NULL, 0, last_loc, print_address_bits);
+  print_one_breakpoint_location (b, NULL, 0, last_loc, print_address_bits, allflag);
 
   /* If this breakpoint has custom print function,
      it's already printed.  Otherwise, print individual
@@ -3919,7 +4142,7 @@ print_one_breakpoint (struct breakpoint 
 	  int n = 1;
 	  for (loc = b->loc; loc; loc = loc->next, ++n)
 	    print_one_breakpoint_location (b, loc, n, last_loc,
-					   print_address_bits);
+					   print_address_bits, allflag);
 	}
     }
 }
@@ -3956,7 +4179,7 @@ do_captured_breakpoint_query (struct ui_
       if (args->bnum == b->number)
 	{
 	  int print_address_bits = breakpoint_address_bits (b);
-	  print_one_breakpoint (b, &dummy_loc, print_address_bits);
+	  print_one_breakpoint (b, &dummy_loc, print_address_bits, 0);
 	  return GDB_RC_OK;
 	}
     }
@@ -4072,7 +4295,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_loc, print_address_bits);
+	  print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
       }
   
   do_cleanups (bkpttbl_chain);
@@ -4120,29 +4343,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 (struct gdbarch *gdbarch, CORE_ADDR pc,
+describe_other_breakpoints (struct gdbarch *gdbarch,
+			    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)
@@ -4150,7 +4378,7 @@ describe_other_breakpoints (struct gdbar
       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);
@@ -4179,10 +4407,12 @@ describe_other_breakpoints (struct gdbar
    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;
@@ -4216,6 +4446,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.
@@ -4223,7 +4467,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;
@@ -4235,9 +4481,10 @@ check_duplicates_for (CORE_ADDR address,
 	&& b->owner->enable_state != bp_startup_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)
@@ -4270,10 +4517,11 @@ check_duplicates_for (CORE_ADDR address,
 		&& b->owner->enable_state != bp_disabled
 		&& b->owner->enable_state != bp_call_disabled
 		&& b->owner->enable_state != bp_startup_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__,
@@ -4295,7 +4543,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
@@ -4518,6 +4766,9 @@ set_raw_breakpoint (struct gdbarch *gdba
   if (!loc_gdbarch)
     loc_gdbarch = b->gdbarch;
 
+  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
@@ -4530,6 +4781,11 @@ set_raw_breakpoint (struct gdbarch *gdba
   b->loc->gdbarch = loc_gdbarch;
   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;
@@ -4577,7 +4833,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;
@@ -4650,7 +4907,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);
 }
 
@@ -4686,7 +4944,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);
 }
 
@@ -4719,11 +4978,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
 	)
       {
@@ -4754,6 +5014,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))
@@ -4957,6 +5218,7 @@ create_catchpoint (struct gdbarch *gdbar
   sal.pc = 0;
   sal.symtab = NULL;
   sal.line = 0;
+  sal.sspace = current_symbol_space;
 
   b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
   set_breakpoint_count (breakpoint_count + 1);
@@ -5138,6 +5400,9 @@ disable_breakpoints_before_startup (void
 
   ALL_BREAKPOINTS (b)
     {
+      if (b->sspace != current_symbol_space)
+	continue;
+
       if ((b->type == bp_breakpoint
 	   || b->type == bp_hardware_breakpoint)
 	  && breakpoint_enabled (b))
@@ -5150,7 +5415,7 @@ disable_breakpoints_before_startup (void
   if (found)
     update_global_location_list (0);
 
-  executing_startup = 1;
+  current_symbol_space->executing_startup = 1;
 }
 
 void
@@ -5159,10 +5424,13 @@ enable_breakpoints_after_startup (void)
   struct breakpoint *b;
   int found = 0;
 
-  executing_startup = 0;
+  current_symbol_space->executing_startup = 0;
 
   ALL_BREAKPOINTS (b)
     {
+      if (b->sspace != current_symbol_space)
+	continue;
+
       if ((b->type == bp_breakpoint
 	   || b->type == bp_hardware_breakpoint)
 	  && b->enable_state == bp_startup_disabled)
@@ -5227,6 +5495,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;
@@ -5236,6 +5505,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;
@@ -5418,6 +5688,8 @@ add_location_to_breakpoint (struct break
   loc->requested_address = sal->pc;
   loc->address = adjust_breakpoint_address (loc->gdbarch,
 					    loc->requested_address, b->type);
+  loc->sspace = sal->sspace;
+  gdb_assert (loc->sspace != NULL);
   loc->section = sal->section;
 
   set_breakpoint_location_function (loc);
@@ -5452,7 +5724,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)
@@ -5492,6 +5767,8 @@ create_breakpoint (struct gdbarch *gdbar
 	error (_("Hardware breakpoints used exceeds limit."));
     }
 
+  gdb_assert (sals.nelts > 0);
+
   for (i = 0; i < sals.nelts; ++i)
     {
       struct symtab_and_line sal = sals.sals[i];
@@ -5504,7 +5781,7 @@ create_breakpoint (struct gdbarch *gdbar
 	    loc_gdbarch = gdbarch;
 
 	  describe_other_breakpoints (loc_gdbarch,
-				      sal.pc, sal.section, thread);
+				      sal.sspace, sal.pc, sal.section, thread);
 	}
 
       if (i == 0)
@@ -5520,7 +5797,9 @@ create_breakpoint (struct gdbarch *gdbar
 	  b->enable_state = enabled ? bp_enabled : bp_disabled;
 	  b->disposition = disposition;
 
-	  if (enabled && executing_startup
+	  b->sspace = sals.sals[0].sspace;
+
+	  if (enabled && b->sspace->executing_startup
 	      && (b->type == bp_breakpoint
 		  || b->type == bp_hardware_breakpoint))
 	    b->enable_state = bp_startup_disabled;
@@ -5570,20 +5849,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)
 {
@@ -5592,6 +5870,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.  */
@@ -5604,9 +5883,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
@@ -5616,6 +5902,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;      
     }
 
@@ -5626,6 +5913,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))
 	    {
@@ -5669,7 +5961,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
@@ -5761,6 +6054,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
@@ -6079,8 +6373,9 @@ break_command_really (struct gdbarch *gd
       b->condition_not_parsed = 1;
       b->ops = ops;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
+      b->sspace = current_symbol_space;
 
-      if (enabled && executing_startup
+      if (enabled && b->sspace->executing_startup
 	  && (b->type == bp_breakpoint
 	      || b->type == bp_hardware_breakpoint))
 	b->enable_state = bp_startup_disabled;
@@ -6153,19 +6448,25 @@ set_breakpoint (struct gdbarch *gdbarch,
 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.  */
@@ -6216,10 +6517,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);
 	    }
 	}
     }
@@ -6410,6 +6716,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;
@@ -7093,7 +7401,8 @@ create_ada_exception_breakpoint (struct 
       if (!loc_gdbarch)
 	loc_gdbarch = gdbarch;
 
-      describe_other_breakpoints (loc_gdbarch, sal.pc, sal.section, -1);
+      describe_other_breakpoints (loc_gdbarch,
+				  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.
@@ -7210,6 +7519,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."));
 
@@ -7273,13 +7583,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)
@@ -7448,8 +7760,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;
@@ -7833,7 +8149,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;
@@ -7870,12 +8187,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)
     {
@@ -7900,6 +8217,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,
@@ -7933,29 +8254,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:
@@ -8028,6 +8351,7 @@ breakpoint_re_set_one (void *bint)
       break;
     }
 
+  do_cleanups (cleanups);
   return 0;
 }
 
@@ -8038,9 +8362,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 */
@@ -8055,6 +8382,8 @@ breakpoint_re_set (void)
 
   jit_breakpoint_re_set ();
 
+  do_cleanups (old_chain);
+
   create_overlay_event_breakpoint ("_ovly_debug_event");
   create_longjmp_master_breakpoint ("longjmp");
   create_longjmp_master_breakpoint ("_longjmp");
@@ -8073,6 +8402,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;
     }
 }
 
@@ -8443,14 +8778,16 @@ decode_line_spec_1 (char *string, int fu
    someday.  */
 
 void *
-deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
+deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch,
+				  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 (gdbarch, bp_tgt) != 0)
     {
       /* Could not insert the breakpoint.  */
@@ -8483,7 +8820,8 @@ static struct gdbarch *single_step_gdbar
 /* Create and insert a breakpoint for software single step.  */
 
 void
-insert_single_step_breakpoint (struct gdbarch *gdbarch, CORE_ADDR next_pc)
+insert_single_step_breakpoint (struct gdbarch *gdbarch,
+			       struct address_space *aspace, CORE_ADDR next_pc)
 {
   void **bpt_p;
 
@@ -8506,7 +8844,7 @@ insert_single_step_breakpoint (struct gd
      corresponding changes elsewhere where single step breakpoints are
      handled, however.  So, for now, we use this.  */
 
-  *bpt_p = deprecated_insert_raw_breakpoint (gdbarch, next_pc);
+  *bpt_p = deprecated_insert_raw_breakpoint (gdbarch, aspace, next_pc);
   if (*bpt_p == NULL)
     error (_("Could not insert single-step breakpoint at %s"),
 	     paddress (gdbarch, next_pc));
@@ -8538,14 +8876,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-09-03 03:00:13.000000000 +0100
+++ src/gdb/exec.h	2009-09-03 03:02:39.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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]