This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFC] [1/2] First.3.1 cut at multi-executable support.
- From: Pedro Alves <pedro at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 6 Jul 2009 15:53:44 +0100
- Subject: [RFC] [1/2] First.3.1 cut at multi-executable support.
- References: <200907012210.48993.pedro@codesourcery.com>
Ulrich's current_gdbarch elimination series touched a bunch of
places this patch is also touching, so it didn't apply cleanly
anymore. Here's the same patch refreshed to current head (and retested
on x86_64). Well, the first half of it, due to email size limitations.
gdb/
2009-07-06 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
Add multi-executable/process support to GDB.
* Makefile.in (SFILES): Add symspace.c.
(COMMON_OBS): Add symspace.o.
* symspace.h: New.
* symspace.c: New.
* breakpoint.h (struct bp_target_info) <placed_address_space>: New
field.
(struct bp_location) <sspace>: New field.
(struct breakpoint) <sspace>: New field.
(bpstat_stop_status, breakpoint_here_p)
(moribund_breakpoint_here_p, breakpoint_inserted_here_p)
(regular_breakpoint_inserted_here_p)
(software_breakpoint_inserted_here_p, breakpoint_thread_match)
(set_default_breakpoint): Adjust prototypes.
(remove_breakpoints_pid, breakpoint_symbol_space_exit): Declare.
(insert_single_step_breakpoint, deprecated_insert_raw_breakpoint):
Adjust prototypes.
* breakpoint.c (default_breakpoint_sspace): New.
(breakpoint_restore_shadows): Skip if the address space doesn't
match.
(update_watchpoint): Record the frame's symbol space in the
breakpoint location.
(insert_bp_location): Record the address space in target_info.
Adjust to pass the symbol space to solib_name_from_address.
(breakpoint_symbol_space_exit): New.
(insert_breakpoint_locations): Switch the symbol space and thread
when inserting breakpoints.
(remove_breakpoints_pid): New.
(reattach_breakpoints): Switch to a thread of PID. Ignore
breakpoints of other symbol spaces.
(create_internal_breakpoint): Store the symbol space in the sal.
(create_longjmp_master_breakpoint): Iterate over all symbol
spaces.
(update_breakpoints_after_exec): Ignore breakpoints for other
symbol spaces.
(remove_breakpoint): Rename to ...
(remove_breakpoint_1): ... this. Pass the breakpoints symbol
space to solib_name_from_address.
(remove_breakpoint): New.
(mark_breakpoints_out): Ignore breakpoints from other symbol
spaces.
(breakpoint_init_inferior): Ditto.
(breakpoint_here_p): Add an address space argument and adjust to
use breakpoint_address_match.
(moribund_breakpoint_here_p): Ditto.
(regular_breakpoint_inserted_here_p): Ditto.
(breakpoint_inserted_here_p): Ditto.
(software_breakpoint_inserted_here_p): Ditto.
(breakpoint_thread_match): Ditto.
(bpstat_check_location): Ditto.
(bpstat_stop_status): Ditto.
(print_breakpoint_location): If there's a location to print,
switch the current symbol space.
(print_one_breakpoint_location): Add `allflag' argument.
(print_one_breakpoint): Ditto. Adjust.
(do_captured_breakpoint_query): Adjust.
(breakpoint_1): Adjust.
(breakpoint_has_pc): Also match the symbol space.
(describe_other_breakpoints): Add a symbol space argument and
adjust.
(set_default_breakpoint): Add a symbol space argument. Set
default_breakpoint_sspace.
(breakpoint_address_match): New.
(check_duplicates_for): Add an address space argument, and adjust.
(set_raw_breakpoint): Record the symbol space in the location and
in the breakpoint.
(set_longjmp_breakpoint): Skip longjmp master breakpoints from
other symbol spaces.
(remove_thread_event_breakpoints, remove_solib_event_breakpoints)
(disable_breakpoints_in_shlibs): Skip breakpoints from other
symbol spaces.
(disable_breakpoints_in_unloaded_shlib): Match symbol spaces.
(create_catchpoint): Set the symbol space in the sal.
(clone_momentary_breakpoint): Also copy the symbol space.
(add_location_to_breakpoint): Set the location's symbol space.
(bp_loc_is_permanent): Switch thread and symbol space.
(create_breakpoint): Adjust.
(expand_line_sal_maybe): Expand comment to mention symbol spaces.
Switch thread and symbol space when reading memory.
(parse_breakpoint_sals): Set the symbol space in the sal.
(break_command_really): Ditto.
(skip_prologue_sal): Switch and space.
(resolve_sal_pc): Ditto.
(watch_command_1): Record the symbol space in the sal.
(create_ada_exception_breakpoint): Adjust.
(clear_command): Adjust. Match symbol spaces.
(update_global_location_list): Use breakpoint_address_match.
(breakpoint_re_set_one): Switch thread and space.
(breakpoint_re_set): Save symbol space.
(breakpoint_re_set_thread): Also reset the symbol space.
(deprecated_insert_raw_breakpoint): Add an address space argument.
Adjust.
(insert_single_step_breakpoint): Ditto.
(single_step_breakpoint_inserted_here_p): Ditto.
* exec.h: Include "symspace.h".
(exec_bfd, exec_bfd_mtime): New defines.
(exec_close_1): Declare.
* exec.c: Include "gdbthread.h" and "symspace.h".
(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
(using_exec_ops): New.
(exec_close_1): Make public.
(exec_close): Add description. Remove target sections and close
executables from all symbol spaces.
(exec_file_attach): Add comment.
(add_target_sections): Check on `using_exec_ops' to check if the
target should be pushed.
(remove_target_sections): Only unpush the target if there are no
more target sections in any symbol space.
* gdbcore.h: Include "exec.h".
(exec_bfd, exec_bfd_mtime): Remove declarations.
* frame.h (get_frame_symbol_space, get_frame_address_space)
(frame_unwind_symbol_space): Declare.
* frame.c (struct frame_info) <sspace, aspace>: New fields.
(create_sentinel_frame): Add symbol space argument. Set the
sspace and aspace fields of the frame object.
(get_current_frame, create_new_frame): Adjust.
(get_frame_symbol_space): New.
(frame_unwind_symbol_space): New.
(get_frame_address_space): New.
* stack.c (print_frame_info): Adjust.
(print_frame): Use the frame's symbol space.
* gdbthread.h (any_live_thread_of_process): Declare.
* thread.c (any_live_thread_of_process): New.
(switch_to_thread): Switch the symbol space as well.
(restore_selected_frame): Don't warn if trying to restore frame
level 0.
* inferior.h: Include "symspace.h".
(detach_fork): Declare.
(struct inferior) <aspace, sspace, vfork_parent, vfork_child>
<pending_detach, waiting_for_vfork_done>: New fields.
(find_inferior_pid): Typo.
(find_inferior_id, find_inferior_for_symbol_space): Declare.
(inferior_list): Declare.
* inferior.c: Include "exec.h".
(inferior_list): Make public.
(delete_inferior_1): Always delete thread silently.
(find_inferior_id): Make public.
(find_inferior_for_symbol_space): New.
(print_inferior): Align columns left. Remove header for the the
"current" column. Add symbol space and executable columns. Print
vfork parent/child relationships. Print if there's no selected
inferior.
* objfiles.h: Include "symspace.h".
(struct objfile) <sspace>: New fields.
(symfile_objfile, object_files): Don't declare.
(ALL_SSPACE_OBJFILES): New.
(ALL_SSPACE_OBJFILES_SAFE): New.
(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
(ALL_SSPACE_SYMTABS): New.
(ALL_PRIMARY_SYMTABS): Adjust.
(ALL_SSPACE_PRIMARY_SYMTABS): New.
(ALL_PSYMTABS): Adjust.
(ALL_SSPACE_PSYMTABS): New.
* objfiles.c (object_files): Delete.
(symfile_objfile): Delete.
(allocate_objfile): Set the objfiles symbol space.
* linespec.c (decode_all_digits, decode_dollar): Set the sal's
symbol space.
* source.c (current_source_sspace): New.
(get_current_source_symtab_and_line): Set the sal's symbol space.
(set_current_source_symtab_and_line): Set current_source_sspace.
(select_source_symtab): Ditto. Use ALL_OBJFILES.
(forget_cached_source_info): Iterate over all symbol spaces.
* symfile.c (clear_symtab_users): Adjust.
* symmisc.c (print_symbol_bcache_statistics): Iterate over all
symbol spaces.
(print_objfile_statistics): Ditto.
(maintenance_print_msymbols): Ditto.
(maintenance_print_objfiles): Ditto.
(maintenance_info_symtabs): Ditto.
(maintenance_info_psymtabs): Ditto.
* symtab.h (SYMTAB_SSPACE): New.
(struct symtab_and_line) <sspace>: New field.
* symtab.c (init_sal): Clear the sal's symbol space.
(find_pc_sect_symtab): Set the sal's symbol space. Switch thread
and space.
(append_expanded_sal): Add symbol space argument. Iterate over
all symbol spaces.
(expand_line_sal): Iterate over all symbol spaces. Switch symbol
space.
* target.h (enum target_waitkind) <TARGET_WAITKIND_VFORK_DONE>: New.
(struct target_ops) <to_thread_address_space>: New field.
(target_thread_address_space): Define.
* target.c (target_detach): Only remove breakpoints from the
inferior we're detaching.
(target_thread_address_space): New.
* top.c (any_thread_of): Delete.
(kill_or_detach): Use any_thread_of_process.
* solist.h (struct so_list) <sspace>: New field.
* solib.h (solib_name_from_address): Adjust prototype.
* solib.c (so_list_head): Replace with a macro referencing the
symbol space.
(update_solib_list): Set the so's symbol space.
(solib_name_from_address): Add a symbol space argument and adjust.
* solib-svr4.c (struct svr4_info) <pid>: Delete field.
<interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low>
<interp_plt_sect_high>: New fields.
(svr4_info_p): Delete.
(svr4_info): Delete.
(solib_svr4_sspace_data): New.
(get_svr4_info): Rewrite.
(svr4_sspace_data_cleanup): New.
(open_symbol_file_object): Adjust.
(svr4_default_sos): Adjust.
(svr4_fetch_objfile_link_map): Adjust.
(interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low)
(interp_plt_sect_high): Delete.
(svr4_in_dynsym_resolve_code): Adjust.
(enable_break): Adjust.
(svr4_clear_solib): Revert bit that removed the svr4_info here.
(_initialize_svr4_solib): Register solib_svr4_sspace_data. Don't
install an inferior_exit observer anymore.
* printcmd.c (struct display) <sspace>: New field.
(display_command): Set the display's sspace.
(do_one_display): Match the display's sspace.
(display_uses_solib_p): Ditto.
* linux-fork.c (detach_fork): Moved to infrun.c.
(_initialize_linux_fork): Moved "detach-on-fork" command to
infrun.c.
* infrun.c (detach_fork): Moved from linux-fork.c.
(proceed_after_vfork_done): New.
(handle_vfork_child_exec_or_exit): New.
(follow_exec_mode_replace, follow_exec_mode_keep)
(follow_exec_mode_names, follow_exec_mode_string)
(show_follow_exec_mode_string): New.
(follow_exec): New. Reinstate the mark_breakpoints_out call.
Remove shared libraries before attaching new executable. If user
wants to keep the symbol space, keep it.
(displaced_step_fixup): Adjust to pass an address space to the
breakpoints module.
(resume): Ditto.
(clear_proceed_status): In all-stop mode, always clear the proceed
status of all threads.
(prepare_to_proceed): Adjust to pass an address space to the
breakpoints module.
(proceed): Ditto.
(adjust_pc_after_break): Ditto.
(handle_inferior_event): When handling a process exit, switch the
symbol space to the inferior's that had exited. Call
handle_vfork_child_exec_or_exit. Adjust to pass an address space
to the breakpoints module. In non-stop mode, when following a
fork, also resume the other branch. Handle
TARGET_WAITKIND_VFORK_DONE. Set the symbol space in sals.
(normal_stop): Prune symbol spaces.
(_initialize_infrun): Install the new "follow-exec-mode" command.
"detach-on-fork" moved here.
* regcache.h (get_regcache_aspace): Declare.
* regcache.c (struct regcache) <aspace>: New field.
(regcache_xmalloc): Clear the aspace.
(get_regcache_aspace): New.
(regcache_cpy): Copy the aspace field.
(regcache_cpy_no_passthrough): Ditto.
(get_thread_regcache): Fetch the thread's address space from the
target, and store it in the regcache.
* infcall.c (call_function_by_hand): Set the sal's sspace.
* arch-utils.c (default_has_shared_address_space): New.
* arch-utils.h (default_has_shared_address_space): Declare.
* gdbarch.sh (has_shared_address_space): New.
* gdbarch.h, gdbarch.c: Regenerate.
* linux-tdep.c: Include auxv.h, target.h, elf/common.h.
(linux_has_shared_address_space): New.
* arm-tdep.c (arm_software_single_step): Pass the frame's address
space to insert_single_step_breakpoint.
* arm-linux-tdep.c (arm_linux_software_single_step): Pass the
frame's sspace to breakpoint functions.
* cris-tdep.c (crisv32_single_step_through_delay): Ditto.
(cris_software_single_step): Ditto.
* mips-tdep.c (deal_with_atomic_sequence): Add frame argument.
Pass the frame's sspace to breakpoint functions.
(mips_software_single_step): Adjust.
(mips_single_step_through_delay): Adjust.
* rs6000-aix-tdep.c (rs6000_software_single_step): Adjust.
* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Adjust.
* solib-irix.c (enable_break): Adjust to pass the current frame's
address space to breakpoint functions.
* sparc-tdep.c (sparc_software_single_step): Ditto.
* spu-tdep.c (spu_software_single_step): Ditto.
* alpha-tdep.c (alpha_software_single_step): Ditto.
* record.c (record_wait): Adjust to pass an address space to the
breakpoints module.
* fork-child.c (fork_inferior): Set the new inferior's symbol and
address spaces.
* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's symbol
and address spaces.
(inf_ptrace_attach): Set the inferior's symbol and address spaces.
* linux-nat.c: Include "solib.h".
(linux_child_follow_fork): Manage parent and child's symbol and
address spaces. Clone the parent's ssymbol space is necessary.
Don't wait for the vfork to be done here.
(resume_callback): Don't resume a vfork parent.
(linux_nat_resume): Also check for pending events in the
lp->waitstatus field.
(linux_handle_extended_wait): Report TARGET_WAITKIND_VFORK_DONE
events to the core.
(stop_wait_callback): Don't wait for SIGSTOP on vfork parents.
(cancel_breakpoint): Adjust.
* linux-thread-db.c (thread_db_wait): Don't remove thread event
breakpoints here.
(thread_db_mourn_inferior): Don't mark breakpoints out here.
Remove thread event breakpoints after mourning.
* corelow.c (core_open): Set the inferior's symbol and address
spaces.
* remote.c (remote_add_inferior): Set the new inferior's symbol
and address spaces.
(remote_start_remote): Update address spaces.
(extended_remote_create_inferior_1): Don't init the thread list if
we already debugging other inferiors.
* darwin-nat.c (darwin_attach): Set the new inferior's symbol and
address spaces.
* gnu-nat.c (gnu_attach): Ditto.
* go32-nat.c (go32_create_inferior): Ditto.
* inf-ttrace.c (inf_ttrace_follow_fork, inf_ttrace_attach): Ditto.
* monitor.c (monitor_open): Ditto.
* nto-procfs.c (procfs_attach, procfs_create_inferior): Ditto.
* procfs.c (do_attach): Ditto.
* windows-nat.c (do_initial_windows_stuff): Ditto.
* tui/tui-disasm.c: Include "symspace.h".
(tui_set_disassem_content): Pass an address space to
breakpoint_here_p.
gdb/testsuite/
2009-07-06 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
* gdb.base/foll-vfork.exp: Adjust to spell out "follow-fork".
* gdb.base/foll-exec.exp: Adjust to expect a process id before
"Executing new program".
* gdb.base/foll-fork.exp: Adjust to spell out "follow-fork".
* gdb.base/multi-forks.exp: Ditto.
* gdb.base/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.
gdb/doc/
2009-07-06 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Multiple Programs): New node.
(Process): Rename node to...
(Forks): ... this.
---
gdb/Makefile.in | 4
gdb/alpha-tdep.c | 3
gdb/arch-utils.c | 8
gdb/arch-utils.h | 2
gdb/arm-linux-tdep.c | 3
gdb/arm-tdep.c | 3
gdb/breakpoint.c | 571 ++++++++++++++---
gdb/breakpoint.h | 45 +
gdb/corelow.c | 6
gdb/cris-tdep.c | 8
gdb/darwin-nat.c | 2
gdb/doc/gdb.texinfo | 102 +++
gdb/exec.c | 70 +-
gdb/exec.h | 5
gdb/fork-child.c | 6
gdb/frame.c | 46 +
gdb/frame.h | 9
gdb/gdbarch.c | 24
gdb/gdbarch.h | 6
gdb/gdbarch.sh | 3
gdb/gdbcore.h | 7
gdb/gdbthread.h | 4
gdb/gnu-nat.c | 2
gdb/go32-nat.c | 5
gdb/inf-ptrace.c | 4
gdb/inf-ttrace.c | 4
gdb/infcall.c | 1
gdb/inferior.c | 66 +-
gdb/inferior.h | 43 +
gdb/infrun.c | 384 +++++++++++-
gdb/linespec.c | 4
gdb/linux-fork.c | 11
gdb/linux-nat.c | 290 ++++++---
gdb/linux-tdep.c | 18
gdb/linux-thread-db.c | 18
gdb/mips-tdep.c | 10
gdb/monitor.c | 4
gdb/nto-procfs.c | 4
gdb/objfiles.c | 4
gdb/objfiles.h | 68 +-
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 | 142 +---
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 | 3
gdb/stack.c | 6
gdb/symfile.c | 2
gdb/symmisc.c | 32 -
gdb/symspace.c | 890 ++++++++++++++++++++++++++++
gdb/symspace.h | 278 ++++++++
gdb/symtab.c | 64 +-
gdb/symtab.h | 5
gdb/target.c | 23
gdb/target.h | 13
gdb/testsuite/Makefile.in | 2
gdb/testsuite/gdb.base/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 | 16
gdb/tui/tui-disasm.c | 4
gdb/windows-nat.c | 2
84 files changed, 3483 insertions(+), 595 deletions(-)
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2009-07-06 15:30:54.000000000 +0100
+++ src/gdb/Makefile.in 2009-07-06 15:31:19.000000000 +0100
@@ -665,7 +665,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-07-06 15:31:19.000000000 +0100
@@ -0,0 +1,278 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef SYMSPACE_H
+#define SYMSPACE_H
+
+#include "target.h"
+#include "vec.h"
+
+struct target_ops;
+struct bfd;
+struct objfile;
+struct inferior;
+struct exec;
+struct address_space;
+struct symbol_space_data;
+
+/* A symbol space represents a symbolic view of an address space.
+ Roughly speaking, it holds all the data associated with a
+ non-running-yet program (main executable, main symbols), and when
+ an inferior is running and is bound to it, includes the list of its
+ mapped in shared libraries.
+
+ In the traditional debugging scenario, there's a 1-1 correspondence
+ among symbol spaces, inferiors and address spaces, like so:
+
+ sspace1 (prog1) <--> inf1(pid1) <--> aspace1
+
+ In the case of debugging more than one traditional unix process or
+ program, we still have:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |----------------------------------------|
+ | sspace2 (prog1) | no inf yet | aspace2 |
+ |-----------------+------------+---------|
+ | sspace3 (prog2) | inf2(pid2) | aspace3 |
+ |-----------------+------------+---------|
+
+ In the former example, if inf1 forks (and GDB stays attached to
+ both processes), the new child will have its own symbol and address
+ spaces. Like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ However, had inf1 from the latter case vforked instead, it would
+ share the symbol and address spaces with its parent, until it execs
+ or exits, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ | | inf2(pid2) | |
+ |-----------------+------------+---------|
+
+ When the vfork child execs, it is finally given new symbol and
+ address spaces.
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ There are targets where the OS (if any) doesn't provide memory
+ management or VM protection, where all inferiors share the same
+ address space --- e.g. uClinux. GDB models by having all inferiors
+ share the same address space, but, giving each its own symbol
+ space, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | |
+ |-----------------+------------+ |
+ | sspace2 (prog1) | inf2(pid2) | aspace1 |
+ |-----------------+------------+ |
+ | sspace3 (prog2) | inf3(pid3) | |
+ |-----------------+------------+---------|
+
+ The address space sharing matters for run control and breakpoints
+ management. E.g., did we just hit a known breakpoint that we need
+ to step over? Is this breakpoint a duplicate of this other one, or
+ do I need to insert a trap?
+
+ Then, there are targets where all symbols look the same for all
+ inferiors, although each has its own address space, as e.g.,
+ Ericsson DICOS. In such case, the model is:
+
+ |---------+------------+---------|
+ | | inf1(pid1) | aspace1 |
+ | +------------+---------|
+ | sspace | inf2(pid2) | aspace2 |
+ | +------------+---------|
+ | | inf3(pid3) | aspace3 |
+ |---------+------------+---------|
+
+ Note however, that the DICOS debug API takes care of making GDB
+ believe that breakpoints are "global". That is, although each
+ process does have its own private copy of data symbols (just like a
+ bunch of forks), to the breakpoints module, all processes share a
+ single address space, so all breakpoints set at the same address
+ are duplicates of each other, even breakpoints set in the data
+ space (e.g., call dummy breakpoints placed on stack). This allows
+ a simplification in the spaces implementation: we avoid caring for
+ a many-many links between address and symbol spaces. Either
+ there's a single address space bound to the symbol space
+ (traditional unix/uClinux), or, in the DICOS case, the address
+ space bound to the symbol space is mostly ignored. */
+
+/* The symbol space structure. */
+
+struct symbol_space
+ {
+ /* Pointer to next in linked list. */
+ struct symbol_space *next;
+
+ /* Unique ID number. */
+ int num;
+
+ /* The main executable loaded into this symbol space. This is
+ managed by the exec target. */
+
+ /* The BFD handle for the main executable. */
+ bfd *ebfd;
+ /* The last-modified time, from when the exec was brought in. */
+ long ebfd_mtime;
+
+ /* The address space attached to this symbol space. More than one
+ symbol space may be bound to the same address space. In the
+ traditional unix-like debugging scenario, this will usually
+ match the address space bound to the inferior, and is mostly
+ used by the breakpoints module for address matches. If the
+ target shares a symbol space for all inferiors and breakpoints
+ are global, then this field is ignored (we don't currently
+ support inferiors sharing a symbol space if the target doesn't
+ make breakpoints global). */
+ struct address_space *aspace;
+
+ /* The object file that the main symbol table was loaded from
+ (e.g. the argument to the "symbol-file" or "file" command). */
+ struct objfile *symfile_object_file;
+
+ /* All known objfiles are kept in a linked list. This points to
+ the root of this list. */
+ struct objfile *objfiles;
+
+ /* The set of target sections matching the sections mapped into
+ this symbol space. Managed by both exec_ops and solib.c. */
+ struct target_section_table target_sections;
+
+ /* List of shared objects mapped into this space. Managed by
+ solib.c. */
+ struct so_list *so_list;
+
+ /* True if this was an auto-created sspace, e.g. created from
+ following a fork/exec; false, if this sspace was manually added
+ by the user, and should not be pruned automatically. */
+ int removable;
+
+ /* Per sspace data-pointers required by other GDB modules. */
+ void **data;
+ unsigned num_data;
+ };
+
+/* The object file that the main symbol table was loaded from (e.g. the
+ argument to the "symbol-file" or "file" command). */
+
+#define symfile_objfile current_symbol_space->symfile_object_file
+
+/* All known objfiles are kept in a linked list. This points to the
+ root of this list. */
+#define object_files current_symbol_space->objfiles
+
+/* The set of target sections matching the sections mapped into the
+ current symbol address space. */
+#define current_target_sections (¤t_symbol_space->target_sections)
+
+/* The list of all symbol spaces. There's always at least one. */
+extern struct symbol_space *symbol_spaces;
+
+/* The current symbol space. This is always non-null. */
+extern struct symbol_space *current_symbol_space;
+
+#define ALL_SSPACES(sspace) \
+ for ((sspace) = symbol_spaces; (sspace) != NULL; (sspace) = (sspace)->next)
+
+/* Add a new empty symbol space, and assign ASPACE to it. Returns the
+ pointer to the new object. */
+extern struct symbol_space *add_symbol_space (struct address_space *aspace);
+
+/* Release SSPACE and removes it from the sspace list. */
+extern void remove_symbol_space (struct symbol_space *sspace);
+
+/* Returns the number of symbol spaces listed. */
+extern int number_of_symbol_spaces (void);
+
+/* Copies symbol space SRC to DEST. Copies the main executable file,
+ and the main symbol file. Returns DEST. */
+extern struct symbol_space *clone_symbol_space (struct symbol_space *dest,
+ struct symbol_space *src);
+
+/* Save the current symbol space so that it may be restored by a later
+ call to do_cleanups. Returns the struct cleanup pointer needed for
+ later doing the cleanup. */
+extern struct cleanup *save_current_symbol_space (void);
+
+/* Sets SSPACE as the current symbol space. This is usually used
+ instead of set_current_space_and_thread when the current
+ thread/inferior is not important for the operations that follow.
+ E.g., when accessing the raw symbol tables. If memory access is
+ required, then you should use switch_to_symbol_space_and_thread.
+ Otherwise, it is the caller's responsibility to make sure that the
+ currently selected inferior/thread matches the selected symbol
+ space. */
+extern void set_current_symbol_space (struct symbol_space *sspace);
+
+/* Saves the current thread (may be null), frame and symbol space in
+ the current cleanup chain. */
+extern struct cleanup *save_current_space_and_thread (void);
+
+/* Switches full context to symbol space SSPACE. Switches to the
+ first thread found bound to SSPACE. */
+extern void switch_to_symbol_space_and_thread (struct symbol_space *sspace);
+
+/* Create a new address space object, and add it to the list. */
+extern struct address_space *new_address_space (void);
+
+/* Maybe create a new address space object, and add it to the list, or
+ return a pointer to an existing address space, in case inferiors
+ share an address space. */
+extern struct address_space *maybe_new_address_space (void);
+
+/* Update all symbol spaces matching to address spaces. The user may
+ have created several symbol spaces, and loaded executables into
+ them before connecting to the target interface that will create the
+ inferiors. All that happens before GDB has a chance to know if the
+ inferiors will share an address space or not. Call this after
+ having connected to the target interface and having fetched the
+ target description, to fixup the symbol/address spaces
+ mappings. */
+extern void update_address_spaces (void);
+
+/* Prune away automatically added symbol spaces that aren't required
+ anymore. */
+extern void prune_symbol_spaces (void);
+
+/* Keep a registry of per-sspace data-pointers required by other GDB
+ modules. */
+
+extern const struct symbol_space_data *register_symbol_space_data (void);
+extern const struct symbol_space_data *register_symbol_space_data_with_cleanup
+ (void (*cleanup) (struct symbol_space *, void *));
+extern void clear_symbol_space_data (struct symbol_space *sspace);
+extern void set_symbol_space_data (struct symbol_space *sspace,
+ const struct symbol_space_data *data, void *value);
+extern void *symbol_space_data (struct symbol_space *sspace,
+ const struct symbol_space_data *data);
+
+#endif
Index: src/gdb/symspace.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.c 2009-07-06 15:31:19.000000000 +0100
@@ -0,0 +1,890 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "solib.h"
+#include "gdbthread.h"
+
+/* The last symbol space number assigned. */
+int last_symbol_space_num = 0;
+
+/* The head of the symbol spaces list. */
+struct symbol_space *symbol_spaces;
+
+/* Pointer to the current symbol space. */
+struct symbol_space *current_symbol_space;
+
+/* The last address space number assigned. */
+static int highest_address_space_num;
+
+/* Prototypes for local functions */
+
+static void symbol_space_alloc_data (struct symbol_space *);
+static void symbol_space_free_data (struct symbol_space *);
+
+
+/* An address space. Currently this is not used for much other than
+ for comparing if sspaces/inferior/threads see the same address
+ space. */
+
+struct address_space
+{
+ int num;
+};
+
+/* Create a new address space object, and add it to the list. */
+
+struct address_space *
+new_address_space (void)
+{
+ struct address_space *aspace;
+
+ aspace = XZALLOC (struct address_space);
+ aspace->num = ++highest_address_space_num;
+
+ return aspace;
+}
+
+/* Maybe create a new address space object, and add it to the list, or
+ return a pointer to an existing address space, in case inferiors
+ share an address space on this target system. */
+
+struct address_space *
+maybe_new_address_space (void)
+{
+ int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
+
+ if (shared_aspace)
+ {
+ /* Just return the first in the list. */
+ return symbol_spaces->aspace;
+ }
+
+ return new_address_space ();
+}
+
+static void
+free_address_space (struct address_space *aspace)
+{
+ xfree (aspace);
+}
+
+/* Start counting over from scratch. */
+
+static void
+init_address_spaces (void)
+{
+ highest_address_space_num = 0;
+}
+
+
+
+/* Add a new empty symbol space to the symbol space list, and binds it
+ to ASPACE. Returns the pointer to the new object. */
+
+struct symbol_space *
+add_symbol_space (struct address_space *aspace)
+{
+ struct symbol_space *sspace;
+
+ sspace = XZALLOC (struct symbol_space);
+
+ sspace->num = ++last_symbol_space_num;
+ sspace->aspace = aspace;
+
+ symbol_space_alloc_data (sspace);
+
+ sspace->next = symbol_spaces;
+ symbol_spaces = sspace;
+
+ return sspace;
+}
+
+/* Releases symbol space SSPACE, and all its contents (shared
+ libraries, objfiles, and any other references to the sspace in
+ other modules). It is an internal error to call this when SSPACE
+ is the current symbol space, since there should always be a symbol
+ space. */
+
+static void
+release_symbol_space (struct symbol_space *sspace)
+{
+ struct cleanup *old_chain = save_current_symbol_space ();
+
+ gdb_assert (sspace != current_symbol_space);
+
+ set_current_symbol_space (sspace);
+
+ breakpoint_symbol_space_exit (sspace);
+ no_shared_libraries (NULL, 0);
+ exec_close_1 ();
+ free_all_objfiles ();
+ if (!gdbarch_has_shared_address_space (target_gdbarch))
+ free_address_space (sspace->aspace);
+ resize_section_table (&sspace->target_sections,
+ -resize_section_table (&sspace->target_sections, 0));
+ /* Discard any data modules have associated with the sspace. */
+ symbol_space_free_data (sspace);
+ xfree (sspace);
+
+ do_cleanups (old_chain);
+}
+
+/* Unlinks SSPACE from the sspace list, and releases it. */
+
+void
+remove_symbol_space (struct symbol_space *sspace)
+{
+ struct symbol_space *ss, **ss_link;
+
+ ss = symbol_spaces;
+ ss_link = &symbol_spaces;
+ while (ss)
+ {
+ if (ss != sspace)
+ {
+ ss_link = &ss->next;
+ ss = *ss_link;
+ continue;
+ }
+
+ *ss_link = ss->next;
+ release_symbol_space (ss);
+ ss = *ss_link;
+ }
+}
+
+/* Copies symbol space SRC to DEST. Copies the main executable file,
+ and the main symbol file. Returns DEST. */
+
+struct symbol_space *
+clone_symbol_space (struct symbol_space *dest, struct symbol_space *src)
+{
+ struct symbol_space *new_sspace;
+ struct cleanup *old_chain;
+
+ old_chain = save_current_symbol_space ();
+
+ set_current_symbol_space (dest);
+
+ if (src->ebfd != NULL)
+ exec_file_attach (bfd_get_filename (src->ebfd), 0);
+
+ if (src->symfile_object_file != NULL)
+ symbol_file_add_main (src->symfile_object_file->name, 0);
+
+ do_cleanups (old_chain);
+ return dest;
+}
+
+/* Sets SSPACE as the current symbol space. It is the caller's
+ responsibility to make sure that the currently selected
+ inferior/thread matches the selected symbol space. */
+
+void
+set_current_symbol_space (struct symbol_space *sspace)
+{
+ if (current_symbol_space == sspace)
+ return;
+
+ gdb_assert (sspace != NULL);
+
+ current_symbol_space = sspace;
+
+ /* Different symbols change our view of the frame chain. */
+ reinit_frame_cache ();
+}
+
+/* A cleanups callback, helper for save_current_symbol_space
+ below. */
+
+static void
+restore_symbol_space (void *arg)
+{
+ struct symbol_space *saved_sspace = arg;
+ set_current_symbol_space (saved_sspace);
+}
+
+/* Save the current symbol space so that it may be restored by a later
+ call to do_cleanups. Returns the struct cleanup pointer needed for
+ later doing the cleanup. */
+
+struct cleanup *
+save_current_symbol_space (void)
+{
+ struct cleanup *old_chain = make_cleanup (restore_symbol_space,
+ current_symbol_space);
+ return old_chain;
+}
+
+/* Find symbol space number NUM; returns NULL if not found. */
+
+static struct symbol_space *
+find_symbol_space_by_num (int num)
+{
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->num == num)
+ return sspace;
+
+ return NULL;
+}
+
+/* Implementation of the "symbol-space SSPACE" command (aliased
+ "sspace"). Switching to a symbol space implicitly switches to the
+ first thread/inferior that is bound to it, unless there's none. */
+
+static void
+symbol_space_command (char *args, int from_tty)
+{
+ int num;
+ struct inferior *inf;
+ struct symbol_space *sspace;
+
+ if (symbol_spaces == NULL)
+ error (_("No spaces"));
+
+ num = parse_and_eval_long (args);
+
+ sspace = find_symbol_space_by_num (num);
+
+ if (sspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+
+ set_current_symbol_space (sspace);
+
+ inf = find_inferior_for_symbol_space (sspace);
+
+ if (inf == NULL)
+ {
+ switch_to_thread (null_ptid);
+
+ if (sspace->ebfd)
+ printf_filtered (_("[Switching to sspace %d (%s)]\n"),
+ sspace->num, bfd_get_filename (sspace->ebfd));
+ else
+ printf_filtered (_("[Switching to sspace %d]\n"), sspace->num);
+ return;
+ }
+
+ if (inf->pid != ptid_get_pid (inferior_ptid))
+ {
+ struct thread_info *tp;
+
+ tp = any_thread_of_process (inf->pid);
+ if (!tp)
+ {
+ switch_to_thread (null_ptid);
+ error (_("Inferior has no threads."));
+ }
+
+ switch_to_thread (tp->ptid);
+ }
+
+ printf_filtered (_("[Switching to thread %d (%s)] "),
+ pid_to_thread_id (inferior_ptid),
+ target_pid_to_str (inferior_ptid));
+
+ if (is_running (inferior_ptid))
+ ui_out_text (uiout, "(running)\n");
+ else
+ {
+ ui_out_text (uiout, "\n");
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ }
+}
+
+/* add-symbol-space [-copies N] [-exec FILENAME] */
+
+void
+add_symbol_space_command (char *args, int from_tty)
+{
+ int i, copies = 1;
+ char *exec = NULL;
+ char **argv;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ if (args)
+ {
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
+
+ for (; *argv != NULL; argv++)
+ {
+ if (**argv == '-')
+ {
+ if (strcmp (*argv, "-copies") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -copies");
+ copies = parse_and_eval_long (*argv);
+ }
+ else if (strcmp (*argv, "-exec") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -exec");
+ exec = *argv;
+ }
+ }
+ else
+ error (_("Invalid argument"));
+ }
+ }
+
+ save_current_space_and_thread ();
+
+ for (i = 0; i < copies; ++i)
+ {
+ struct address_space *aspace;
+ struct symbol_space *sspace;
+
+ /* If all inferiors share an address space on this system, this
+ doesn't really return a new address space; otherwise, it
+ really does. */
+ aspace = maybe_new_address_space ();
+ sspace = add_symbol_space (aspace);
+
+ printf_filtered ("Added symbol space %d\n", sspace->num);
+
+ if (exec != NULL)
+ {
+ /* Switch over temporarily, while reading executable and
+ symbols.q */
+ set_current_symbol_space (sspace);
+ switch_to_thread (null_ptid);
+
+ exec_file_attach (exec, from_tty);
+ symbol_file_add_main (exec, from_tty);
+ }
+ }
+
+ do_cleanups (old_chain);
+
+ printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+/* clone-symbol-space [-copies N] [ID] */
+
+void
+clone_symbol_space_command (char *args, int from_tty)
+{
+ int i, copies = 1;
+ char **argv;
+ struct symbol_space *orgspace = NULL;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ if (args)
+ {
+ argv = gdb_buildargv (args);
+ make_cleanup_freeargv (argv);
+
+ for (; *argv != NULL; argv++)
+ {
+ if (**argv == '-')
+ {
+ if (strcmp (*argv, "-copies") == 0)
+ {
+ ++argv;
+ if (!*argv)
+ error ("No argument to -copies");
+ copies = parse_and_eval_long (*argv);
+
+ if (copies < 0)
+ error (_("Invalid copies number"));
+ }
+ }
+ else
+ {
+ if (orgspace == NULL)
+ {
+ int num;
+
+ /* The first non-option (-) argument specified the
+ symbol space ID. */
+ num = parse_and_eval_long (*argv);
+ orgspace = find_symbol_space_by_num (num);
+
+ if (orgspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+ continue;
+ }
+ else
+ error (_("Invalid argument"));
+ }
+ }
+ }
+
+ /* If no symbol space id was specified, then the user wants to clone
+ the current symbol space. */
+ if (orgspace == NULL)
+ orgspace = current_symbol_space;
+
+ save_current_space_and_thread ();
+
+ for (i = 0; i < copies; ++i)
+ {
+ struct address_space *aspace;
+ struct symbol_space *sspace;
+
+ /* If all inferiors share an address space on this system, this
+ doesn't really return a new address space; otherwise, it
+ really does. */
+ aspace = maybe_new_address_space ();
+ sspace = add_symbol_space (aspace);
+
+ printf_filtered ("Added symbol space %d.\n", sspace->num);
+
+ switch_to_thread (null_ptid);
+ clone_symbol_space (sspace, orgspace);
+ }
+
+ do_cleanups (old_chain);
+
+ printf_filtered ("%d symbol spaces added.\n", copies);
+}
+
+/* remove-symbol-space ID */
+
+void
+remove_symbol_space_command (char *args, int from_tty)
+{
+ int num;
+ struct symbol_space *sspace;
+ struct inferior *inf;
+
+ num = parse_and_eval_long (args);
+ sspace = find_symbol_space_by_num (num);
+
+ if (sspace == NULL)
+ error (_("Symbol space ID %d not known."), num);
+
+ if (sspace == current_symbol_space)
+ error (_("Can not remove current symbol space."));
+
+ /* Can't remove a symbol space if inferiors are still bound to
+ it. */
+ inf = find_inferior_for_symbol_space (sspace);
+ if (inf != NULL)
+ error (_("Can not remove symbol space with bound inferiors."));
+
+ remove_symbol_space (sspace);
+}
+
+/* Returns true iff there's no inferior bound to SSPACE. */
+
+static int
+sspace_empty_p (struct symbol_space *sspace)
+{
+ struct inferior *inf;
+
+ if (find_inferior_for_symbol_space (sspace) != NULL)
+ return 0;
+
+ return 1;
+}
+
+/* Prune away automatically added symbol spaces that aren't required
+ anymore. */
+
+void
+prune_symbol_spaces (void)
+{
+ struct symbol_space *ss, **ss_link;
+ struct symbol_space *current = current_symbol_space;
+
+ ss = symbol_spaces;
+ ss_link = &symbol_spaces;
+ while (ss)
+ {
+ if (ss == current
+ || !ss->removable
+ || !sspace_empty_p (ss))
+ {
+ ss_link = &ss->next;
+ ss = *ss_link;
+ continue;
+ }
+
+ *ss_link = ss->next;
+ release_symbol_space (ss);
+ ss = *ss_link;
+ }
+}
+
+/* Prints the list of symbol spaces and their details on UIOUT. If
+ REQUESTED is not -1, it's the ID of the sspace that should be
+ printed. Otherwise, all spaces are printed. */
+
+static void
+print_symbol_space (struct ui_out *uiout, int requested)
+{
+ struct symbol_space *sspace;
+ int count = 0;
+ struct cleanup *old_chain;
+
+ /* Might as well prune away unneeded ones, so the user doesn't even
+ seem them. */
+ prune_symbol_spaces ();
+
+ /* Compute number of sspaces we will print. */
+ ALL_SSPACES (sspace)
+ {
+ if (requested != -1 && sspace->num != requested)
+ continue;
+
+ ++count;
+ }
+
+ /* There should always be at least one. */
+ gdb_assert (count > 0);
+
+ old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, count,
+ "sspaces");
+ ui_out_table_header (uiout, 1, ui_left, "current", "");
+ ui_out_table_header (uiout, 4, ui_left, "id", "Id");
+ ui_out_table_header (uiout, 17, ui_left, "exec", "Main Program");
+ ui_out_table_body (uiout);
+
+ ALL_SSPACES (sspace)
+ {
+ struct cleanup *chain2;
+ struct inferior *inf;
+ int printed_header;
+
+ if (requested != -1 && requested != sspace->num)
+ continue;
+
+ chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+ if (sspace == current_symbol_space)
+ ui_out_field_string (uiout, "current", "*");
+ else
+ ui_out_field_skip (uiout, "current");
+
+ ui_out_field_int (uiout, "id", sspace->num);
+
+ if (sspace->ebfd)
+ ui_out_field_string (uiout, "exec",
+ bfd_get_filename (sspace->ebfd));
+ else
+ ui_out_field_skip (uiout, "exec");
+
+ /* Print extra info that doesn't really fit in tabular form.
+ Currently, we print the list of inferiors bound to a sspace.
+ There can be more than one inferior bound to the same sspace,
+ e.g., both parent/child inferiors in a vfork, or, on targets
+ that share sspaces between inferiors. */
+ printed_header = 0;
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->sspace == sspace)
+ {
+ if (!printed_header)
+ {
+ printed_header = 1;
+ printf_filtered ("\n\tBound inferiors: ID %d (%s)",
+ inf->num,
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+ }
+ else
+ printf_filtered (", ID %d (%s)",
+ inf->num,
+ target_pid_to_str (pid_to_ptid (inf->pid)));
+ }
+
+ ui_out_text (uiout, "\n");
+ do_cleanups (chain2);
+ }
+
+ do_cleanups (old_chain);
+}
+
+/* Boolean test for an already-known symbol space id. */
+
+static int
+valid_symbol_space_id (int num)
+{
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->num == num)
+ return 1;
+
+ return 0;
+}
+
+/* If ARGS is NULL or empty, print information about all symbol
+ spaces. Otherwise, ARGS is a text representation of a LONG
+ indicating which the symbol space to print information about. */
+
+static void
+info_symbol_spaces_command (char *args, int from_tty)
+{
+ int requested = -1;
+
+ if (args && *args)
+ {
+ requested = parse_and_eval_long (args);
+ if (!valid_symbol_space_id (requested))
+ error (_("Symbol space ID %d not known."), requested);
+ }
+
+ print_symbol_space (uiout, requested);
+}
+
+/* Simply returns the count of symbol spaces. */
+
+int
+number_of_symbol_spaces (void)
+{
+ struct symbol_space *sspace;
+ int count = 0;
+
+ ALL_SSPACES (sspace)
+ count++;
+
+ return count;
+}
+
+/* Update all symbol spaces matching to address spaces. The user may
+ have created several symbol spaces, and loaded executables into
+ them before connecting to the target interface that will create the
+ inferiors. All that happens before GDB has a chance to know if the
+ inferiors will share an address space or not. Call this after
+ having connected to the target interface and having fetched the
+ target description, to fixup the symbol/address spaces mappings.
+
+ It is assumed that there are no bound inferiors yet, otherwise,
+ they'd be left with stale referenced to released aspaces. */
+
+void
+update_address_spaces (void)
+{
+ int shared_aspace = gdbarch_has_shared_address_space (target_gdbarch);
+ struct address_space *aspace = NULL;
+ struct symbol_space *sspace;
+
+ init_address_spaces ();
+
+ ALL_SSPACES (sspace)
+ {
+ free_address_space (sspace->aspace);
+
+ if (shared_aspace)
+ {
+ if (aspace == NULL)
+ aspace = new_address_space ();
+ sspace->aspace = aspace;
+ }
+ else
+ sspace->aspace = new_address_space ();
+ }
+}
+
+/* Save the current symbol space so that it may be restored by a later
+ call to do_cleanups. Returns the struct cleanup pointer needed for
+ later doing the cleanup. */
+
+struct cleanup *
+save_current_space_and_thread (void)
+{
+ struct cleanup *old_chain;
+
+ /* If restoring to null thread, we need to restore the sspace as
+ well, hence, we need to save the current symbol space first. */
+ old_chain = save_current_symbol_space ();
+ make_cleanup_restore_current_thread ();
+
+ return old_chain;
+}
+
+/* Switches full context to symbol space SSPACE. Switches to the
+ first thread found bound to SSPACE. */
+
+void
+switch_to_symbol_space_and_thread (struct symbol_space *sspace)
+{
+ struct inferior *inf;
+
+ inf = find_inferior_for_symbol_space (sspace);
+ if (inf != NULL)
+ {
+ struct thread_info *tp;
+
+ tp = any_live_thread_of_process (inf->pid);
+ if (tp != NULL)
+ {
+ switch_to_thread (tp->ptid);
+ /* Switching thread switches sspace implicitly. We're
+ done. */
+ return;
+ }
+ }
+
+ switch_to_thread (null_ptid);
+ set_current_symbol_space (sspace);
+}
+
+
+
+/* Keep a registry of per-symbol_space data-pointers required by other GDB
+ modules. */
+
+struct symbol_space_data
+{
+ unsigned index;
+ void (*cleanup) (struct symbol_space *, void *);
+};
+
+struct symbol_space_data_registration
+{
+ struct symbol_space_data *data;
+ struct symbol_space_data_registration *next;
+};
+
+struct symbol_space_data_registry
+{
+ struct symbol_space_data_registration *registrations;
+ unsigned num_registrations;
+};
+
+static struct symbol_space_data_registry symbol_space_data_registry
+ = { NULL, 0 };
+
+const struct symbol_space_data *
+register_symbol_space_data_with_cleanup
+ (void (*cleanup) (struct symbol_space *, void *))
+{
+ struct symbol_space_data_registration **curr;
+
+ /* Append new registration. */
+ for (curr = &symbol_space_data_registry.registrations;
+ *curr != NULL; curr = &(*curr)->next);
+
+ *curr = XMALLOC (struct symbol_space_data_registration);
+ (*curr)->next = NULL;
+ (*curr)->data = XMALLOC (struct symbol_space_data);
+ (*curr)->data->index = symbol_space_data_registry.num_registrations++;
+ (*curr)->data->cleanup = cleanup;
+
+ return (*curr)->data;
+}
+
+const struct symbol_space_data *
+register_symbol_space_data (void)
+{
+ return register_symbol_space_data_with_cleanup (NULL);
+}
+
+static void
+symbol_space_alloc_data (struct symbol_space *sspace)
+{
+ gdb_assert (sspace->data == NULL);
+ sspace->num_data = symbol_space_data_registry.num_registrations;
+ sspace->data = XCALLOC (sspace->num_data, void *);
+}
+
+static void
+symbol_space_free_data (struct symbol_space *sspace)
+{
+ gdb_assert (sspace->data != NULL);
+ clear_symbol_space_data (sspace);
+ xfree (sspace->data);
+ sspace->data = NULL;
+}
+
+void
+clear_symbol_space_data (struct symbol_space *sspace)
+{
+ struct symbol_space_data_registration *registration;
+ int i;
+
+ gdb_assert (sspace->data != NULL);
+
+ for (registration = symbol_space_data_registry.registrations, i = 0;
+ i < sspace->num_data;
+ registration = registration->next, i++)
+ if (sspace->data[i] != NULL && registration->data->cleanup)
+ registration->data->cleanup (sspace, sspace->data[i]);
+
+ memset (sspace->data, 0, sspace->num_data * sizeof (void *));
+}
+
+void
+set_symbol_space_data (struct symbol_space *sspace,
+ const struct symbol_space_data *data,
+ void *value)
+{
+ gdb_assert (data->index < sspace->num_data);
+ sspace->data[data->index] = value;
+}
+
+void *
+symbol_space_data (struct symbol_space *sspace, const struct symbol_space_data *data)
+{
+ gdb_assert (data->index < sspace->num_data);
+ return sspace->data[data->index];
+}
+
+
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_symspace;
+
+void
+_initialize_symspace (void)
+{
+ add_info ("symbol-spaces", info_symbol_spaces_command, _("\
+Info about currently known symbol spaces."));
+ add_info_alias ("sspaces", "symbol-spaces", 0);
+
+ add_com ("symbol-space", no_class, symbol_space_command, _("\
+Change the current symbol space."));
+ add_com_alias ("sspace", "symbol-space", no_class, 0);
+
+ add_com ("add-symbol-space", no_class, add_symbol_space_command, _("\
+Add a new symbol space.\n\
+Usage: add-symbol-space [-copies <N>] [-exec <FILENAME>]\n\
+N is the optional number of spaces to add, default is 1.\n\
+FILENAME is the file name of the main executable to load\n\
+in the new symbol spaces."));
+
+ add_com ("remove-symbol-space", no_class, remove_symbol_space_command, _("\
+Remove symbol-space ID.\n\
+Usage: remove-symbol-space ID\n\
+Trying to remove the current symbol space, or a symbol space that\n\
+has bound inferiors is an error."));
+
+ add_com ("clone-symbol-space", no_class, clone_symbol_space_command, _("\
+Clone symbol space SPACE.\n\
+Usage: clone-symbol-space [-copies <N>] [ID]\n\
+Add N copies of symbol space ID. The new symbol space has the same\n\
+executable loaded as the original space. If -copies is not specified,\n\
+adds 1 copy. If ID is not specified, it is the current symbol space\n\
+that is cloned."));
+
+ /* There's always one symbol space. */
+ current_symbol_space = add_symbol_space (new_address_space ());
+}
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h 2009-07-06 15:30:06.000000000 +0100
+++ src/gdb/breakpoint.h 2009-07-06 15:31:19.000000000 +0100
@@ -166,6 +166,9 @@ enum target_hw_bp_type
struct bp_target_info
{
+ /* Address space at which the breakpoint was placed. */
+ struct address_space *placed_address_space;
+
/* Address at which the breakpoint was placed. This is normally the
same as ADDRESS from the bp_location, except when adjustment
happens in gdbarch_breakpoint_from_pc. The most common form of
@@ -262,6 +265,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
@@ -396,6 +407,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. */
@@ -501,7 +515,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). */
@@ -685,17 +700,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);
@@ -713,7 +728,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);
@@ -744,6 +760,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
@@ -779,6 +797,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);
@@ -866,13 +889,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-07-06 15:30:05.000000000 +0100
+++ src/gdb/breakpoint.c 2009-07-06 15:31:19.000000000 +0100
@@ -117,9 +117,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);
@@ -146,6 +152,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);
@@ -188,7 +195,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);
@@ -401,6 +409,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.
@@ -727,6 +737,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;
@@ -881,6 +895,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
@@ -909,6 +924,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;
@@ -1011,6 +1028,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;
@@ -1090,6 +1109,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)
@@ -1208,7 +1228,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;
@@ -1286,6 +1306,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
@@ -1329,9 +1391,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;
@@ -1341,6 +1408,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);
@@ -1419,6 +1515,30 @@ remove_breakpoints (void)
return 0;
}
+/* Remove breakpoints of process PID. */
+
+int
+remove_breakpoints_pid (int pid)
+{
+ struct bp_location *b;
+ int val;
+ struct inferior *inf = find_inferior_pid (pid);
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->sspace != inf->sspace)
+ continue;
+
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b, mark_uninserted);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
int
remove_hw_watchpoints (void)
{
@@ -1440,17 +1560,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;
@@ -1480,6 +1613,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--;
@@ -1524,8 +1658,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;
@@ -1534,6 +1673,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;
@@ -1545,6 +1686,8 @@ create_longjmp_master_breakpoint (char *
b->enable_state = bp_disabled;
}
update_global_location_list (1);
+
+ do_cleanups (old_chain);
}
void
@@ -1563,10 +1706,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)
{
@@ -1661,17 +1808,22 @@ detach_breakpoints (int pid)
struct bp_location *b;
int val;
struct cleanup *old_chain = save_inferior_ptid ();
+ struct inferior *inf = current_inferior ();
if (pid == PIDGET (inferior_ptid))
error (_("Cannot detach breakpoints of inferior_ptid"));
- /* Set inferior_ptid; remove_breakpoint uses this global. */
+ /* Set inferior_ptid; remove_breakpoint_1 uses this global. */
inferior_ptid = pid_to_ptid (pid);
+
ALL_BP_LOCATIONS (b)
{
+ if (b->sspace != inf->sspace)
+ continue;
+
if (b->inserted)
{
- val = remove_breakpoint (b, mark_inserted);
+ val = remove_breakpoint_1 (b, mark_inserted);
if (val != 0)
{
do_cleanups (old_chain);
@@ -1683,10 +1835,17 @@ detach_breakpoints (int pid)
return 0;
}
+/* Remove the breakpoint location B from the current address space.
+ Note that this is used to detach breakpoints from a child fork.
+ When we get here, the child isn't in the inferior list, and neither
+ do we have objects to represent its address space --- we should
+ *not* look at b->sspace->aspace here. */
+
static int
-remove_breakpoint (struct bp_location *b, insertion_state_t is)
+remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
{
int val;
+ struct cleanup *old_chain;
if (b->owner->enable_state == bp_permanent)
/* Permanent breakpoints cannot be inserted or removed. */
@@ -1764,7 +1923,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)
@@ -1800,6 +1959,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
@@ -1808,7 +1991,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
@@ -1829,6 +2013,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. */
@@ -1836,11 +2021,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:
@@ -1883,6 +2074,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
@@ -1894,7 +2090,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;
@@ -1907,7 +2103,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)
@@ -1926,13 +2123,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;
@@ -1944,7 +2142,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;
@@ -1955,7 +2153,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)
@@ -1972,12 +2171,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;
@@ -1987,7 +2186,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;
@@ -1998,7 +2197,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)
@@ -2010,7 +2210,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;
@@ -2020,7 +2220,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. */
@@ -2037,7 +2238,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)
@@ -2896,7 +3098,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;
@@ -2907,7 +3110,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)
@@ -3131,7 +3335,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;
@@ -3159,7 +3364,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 */
@@ -3214,7 +3419,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. */
@@ -3518,6 +3724,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
@@ -3553,6 +3764,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. */
@@ -3561,7 +3774,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;
@@ -3739,6 +3953,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)
@@ -3872,9 +4098,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
@@ -3898,7 +4125,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);
}
}
}
@@ -3935,7 +4162,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;
}
}
@@ -4051,7 +4278,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);
@@ -4099,29 +4326,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)
@@ -4129,7 +4361,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);
@@ -4157,10 +4389,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;
@@ -4194,6 +4428,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.
@@ -4201,7 +4449,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;
@@ -4212,9 +4462,10 @@ check_duplicates_for (CORE_ADDR address,
&& b->owner->enable_state != bp_call_disabled
&& b->enabled
&& !b->shlib_disabled
- && b->address == address /* address / overlay match */
&& (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address))
{
/* Have we found a permanent breakpoint? */
if (b->owner->enable_state == bp_permanent)
@@ -4246,10 +4497,11 @@ check_duplicates_for (CORE_ADDR address,
if (b->owner->enable_state != bp_permanent
&& b->owner->enable_state != bp_disabled
&& b->owner->enable_state != bp_call_disabled
- && b->enabled && !b->shlib_disabled
- && b->address == address /* address / overlay match */
- && (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && b->enabled && !b->shlib_disabled
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address)
+ && (!overlay_debugging || b->section == section))
{
if (b->inserted)
internal_error (__FILE__, __LINE__,
@@ -4271,7 +4523,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
@@ -4492,6 +4744,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
@@ -4504,6 +4759,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;
@@ -4551,7 +4811,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;
@@ -4624,7 +4885,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);
}
@@ -4649,7 +4911,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);
}
@@ -4682,11 +4945,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
)
{
@@ -4717,6 +4981,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))
@@ -4920,6 +5185,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);
@@ -5144,6 +5410,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;
@@ -5153,6 +5420,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;
@@ -5334,6 +5602,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);
@@ -5368,7 +5638,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)
@@ -5420,7 +5693,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)
@@ -5463,6 +5736,8 @@ create_breakpoint (struct gdbarch *gdbar
b->addr_string
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+ b->sspace = sals.sals[0].sspace;
+
b->ops = ops;
mention (b);
}
@@ -5481,20 +5756,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)
{
@@ -5503,6 +5777,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. */
@@ -5515,9 +5790,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
@@ -5527,6 +5809,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;
}
@@ -5537,6 +5820,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))
{
@@ -5580,7 +5868,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
@@ -5672,6 +5961,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
@@ -5990,6 +6280,7 @@ 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;
mention (b);
}
@@ -6059,19 +6350,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. */
@@ -6122,10 +6419,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);
}
}
}
@@ -6316,6 +6618,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;
@@ -6999,7 +7303,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.
@@ -7116,6 +7421,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."));
@@ -7179,13 +7485,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)
@@ -7354,8 +7662,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;
@@ -7737,7 +8049,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;
@@ -7774,12 +8087,12 @@ breakpoint_re_set_one (void *bint)
int i;
int not_found = 0;
int *not_found_ptr = ¬_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)
{
@@ -7800,6 +8113,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,
@@ -7833,29 +8150,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:
@@ -7927,6 +8246,7 @@ breakpoint_re_set_one (void *bint)
break;
}
+ do_cleanups (cleanups);
return 0;
}
@@ -7937,9 +8257,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 */
@@ -7952,6 +8275,8 @@ breakpoint_re_set (void)
set_language (save_language);
input_radix = save_input_radix;
+ do_cleanups (old_chain);
+
create_overlay_event_breakpoint ("_ovly_debug_event");
create_longjmp_master_breakpoint ("longjmp");
create_longjmp_master_breakpoint ("_longjmp");
@@ -7970,6 +8295,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;
}
}
@@ -8340,14 +8671,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. */
@@ -8380,7 +8713,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;
@@ -8403,7 +8737,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));
@@ -8435,14 +8769,17 @@ remove_single_step_breakpoints (void)
/* Check whether a software single-step breakpoint is inserted at PC. */
static int
-single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
+single_step_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
int i;
for (i = 0; i < 2; i++)
{
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
- if (bp_tgt && bp_tgt->placed_address == pc)
+ if (bp_tgt
+ && breakpoint_address_match (bp_tgt->placed_address_space,
+ bp_tgt->placed_address,
+ aspace, pc))
return 1;
}
Index: src/gdb/exec.h
===================================================================
--- src.orig/gdb/exec.h 2009-07-06 15:30:06.000000000 +0100
+++ src/gdb/exec.h 2009-07-06 15:31:19.000000000 +0100
@@ -21,6 +21,7 @@
#define EXEC_H
#include "target.h"
+#include "symspace.h"
struct target_section;
struct target_ops;
@@ -28,6 +29,9 @@ struct bfd;
extern struct target_ops exec_ops;
+#define exec_bfd current_symbol_space->ebfd
+#define exec_bfd_mtime current_symbol_space->ebfd_mtime
+
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */
@@ -82,5 +86,6 @@ extern void add_target_sections (struct
extern void print_section_info (struct target_section_table *table,
bfd *abfd);
+extern void exec_close_1 (void);
#endif
Index: src/gdb/exec.c
===================================================================
--- src.orig/gdb/exec.c 2009-07-06 15:30:06.000000000 +0100
+++ src/gdb/exec.c 2009-07-06 15:31:19.000000000 +0100
@@ -32,6 +32,8 @@
#include "exec.h"
#include "observer.h"
#include "arch-utils.h"
+#include "gdbthread.h"
+#include "symspace.h"
#include <fcntl.h>
#include "readline/readline.h"
@@ -66,20 +68,8 @@ void _initialize_exec (void);
struct target_ops exec_ops;
-/* The Binary File Descriptor handle for the executable file. */
-
-bfd *exec_bfd = NULL;
-long exec_bfd_mtime = 0;
-
-/* GDB currently only supports a single symbol/address space for the
- whole debug session. When that limitation is lifted, this global
- goes away. */
-static struct target_section_table current_target_sections_1;
-
-/* The set of target sections matching the sections mapped into the
- current inferior's address space. */
-static struct target_section_table *current_target_sections
- = ¤t_target_sections_1;
+/* True if the exec target is pushed on the stack. */
+static int using_exec_ops;
/* Whether to open exec and core files read-only or read-write. */
@@ -105,7 +95,7 @@ exec_open (char *args, int from_tty)
/* Close and clear exec_bfd. If we end up with no target sections to
read memory from, this unpushes the exec_ops target. */
-static void
+void
exec_close_1 (void)
{
if (exec_bfd)
@@ -127,12 +117,17 @@ exec_close_1 (void)
}
}
+/* This is the target_close implementation. Clears all target
+ sections and closes all executable bfds from all symbol spaces. */
+
static void
exec_close (int quitting)
{
int need_symtab_cleanup = 0;
struct vmap *vp, *nxt;
+ using_exec_ops = 0;
+
for (nxt = vmap; nxt != NULL;)
{
vp = nxt;
@@ -163,13 +158,25 @@ exec_close (int quitting)
vmap = NULL;
- /* Delete all target sections. */
- resize_section_table
- (current_target_sections,
- -resize_section_table (current_target_sections, 0));
+ {
+ struct symbol_space *ss;
+ struct cleanup *old_chain;
- /* Remove exec file. */
- exec_close_1 ();
+ old_chain = save_current_symbol_space ();
+ ALL_SSPACES (ss)
+ {
+ set_current_symbol_space (ss);
+
+ /* Delete all target sections. */
+ resize_section_table
+ (current_target_sections,
+ -resize_section_table (current_target_sections, 0));
+
+ exec_close_1 ();
+ }
+
+ do_cleanups (old_chain);
+ }
}
void
@@ -295,7 +302,8 @@ exec_file_attach (char *filename, int fr
set_gdbarch_from_file (exec_bfd);
/* Add the executable's sections to the current address spaces'
- list of sections. */
+ list of sections. This possibly pushes the exec_ops
+ target. */
add_target_sections (sections, sections_end);
xfree (sections);
@@ -465,8 +473,11 @@ add_target_sections (struct target_secti
/* If these are the first file sections we can provide memory
from, push the file_stratum target. */
- if (space == 0)
- push_target (&exec_ops);
+ if (!using_exec_ops)
+ {
+ using_exec_ops = 1;
+ push_target (&exec_ops);
+ }
}
}
@@ -499,7 +510,16 @@ remove_target_sections (bfd *abfd)
/* If we don't have any more sections to read memory from,
remove the file_stratum target from the stack. */
if (old_count + (dest - src) == 0)
- unpush_target (&exec_ops);
+ {
+ struct symbol_space *sspace;
+
+ ALL_SSPACES (sspace)
+ if (sspace->target_sections.sections
+ != sspace->target_sections.sections_end)
+ return;
+
+ unpush_target (&exec_ops);
+ }
}
}