* [v4 1/2] multi-executable support
2009-09-03 2:49 [v4 0/2] multi-executable support Pedro Alves
@ 2009-09-03 2:51 ` Pedro Alves
2009-09-03 2:53 ` [v4 2/2] " Pedro Alves
2009-09-03 2:56 ` [v4 0/2] multi-executable support (.gz) Pedro Alves
2 siblings, 0 replies; 16+ messages in thread
From: Pedro Alves @ 2009-09-03 2:51 UTC (permalink / raw)
To: gdb-patches
2009-09-03 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
Add multi-executable/process support to GDB.
gdb/
* Makefile.in (SFILES): Add symspace.c.
(COMMON_OBS): Add symspace.o.
* symspace.h: New.
* symspace.c: New.
* breakpoint.h (struct bp_target_info) <placed_address_space>: New
field.
(struct bp_location) <sspace>: New field.
(struct breakpoint) <sspace>: New field.
(bpstat_stop_status, breakpoint_here_p)
(moribund_breakpoint_here_p, breakpoint_inserted_here_p)
(regular_breakpoint_inserted_here_p)
(software_breakpoint_inserted_here_p, breakpoint_thread_match)
(set_default_breakpoint): Adjust prototypes.
(remove_breakpoints_pid, breakpoint_symbol_space_exit): Declare.
(insert_single_step_breakpoint, deprecated_insert_raw_breakpoint):
Adjust prototypes.
* breakpoint.c (executing_startup): Delete.
(default_breakpoint_sspace): New.
(breakpoint_restore_shadows): Skip if the address space doesn't
match.
(update_watchpoint): Record the frame's symbol space in the
breakpoint location.
(insert_bp_location): Record the address space in target_info.
Adjust to pass the symbol space to solib_name_from_address.
(breakpoint_symbol_space_exit): New.
(insert_breakpoint_locations): Switch the symbol space and thread
when inserting breakpoints. Don't insert breakpoints in a vfork
parent waiting for vfork done if we're not attached to the vfork
child.
(remove_breakpoints_pid): New.
(reattach_breakpoints): Switch to a thread of PID. Ignore
breakpoints of other symbol spaces.
(create_internal_breakpoint): Store the symbol space in the sal.
(create_longjmp_master_breakpoint): Iterate over all symbol
spaces.
(update_breakpoints_after_exec): Ignore breakpoints for other
symbol spaces.
(remove_breakpoint): Rename to ...
(remove_breakpoint_1): ... this. Pass the breakpoints symbol
space to solib_name_from_address.
(remove_breakpoint): New.
(mark_breakpoints_out): Ignore breakpoints from other symbol
spaces.
(breakpoint_init_inferior): Ditto.
(breakpoint_here_p): Add an address space argument and adjust to
use breakpoint_address_match.
(moribund_breakpoint_here_p): Ditto.
(regular_breakpoint_inserted_here_p): Ditto.
(breakpoint_inserted_here_p): Ditto.
(software_breakpoint_inserted_here_p): Ditto.
(breakpoint_thread_match): Ditto.
(bpstat_check_location): Ditto.
(bpstat_stop_status): Ditto.
(print_breakpoint_location): If there's a location to print,
switch the current symbol space.
(print_one_breakpoint_location): Add `allflag' argument.
(print_one_breakpoint): Ditto. Adjust.
(do_captured_breakpoint_query): Adjust.
(breakpoint_1): Adjust.
(breakpoint_has_pc): Also match the symbol space.
(describe_other_breakpoints): Add a symbol space argument and
adjust.
(set_default_breakpoint): Add a symbol space argument. Set
default_breakpoint_sspace.
(breakpoint_address_match): New.
(check_duplicates_for): Add an address space argument, and adjust.
(set_raw_breakpoint): Record the symbol space in the location and
in the breakpoint.
(set_longjmp_breakpoint): Skip longjmp master breakpoints from
other symbol spaces.
(remove_thread_event_breakpoints, remove_solib_event_breakpoints)
(disable_breakpoints_in_shlibs): Skip breakpoints from other
symbol spaces.
(disable_breakpoints_in_unloaded_shlib): Match symbol spaces.
(create_catchpoint): Set the symbol space in the sal.
(disable_breakpoints_before_startup): Skip breakpoints from other
symbol spaces. Set executing_startup in the current symbol space.
(enable_breakpoints_after_startup): Clear executing_startup in the
current symbol space. Skip breakpoints from other symbol spaces.
(clone_momentary_breakpoint): Also copy the symbol space.
(add_location_to_breakpoint): Set the location's symbol space.
(bp_loc_is_permanent): Switch thread and symbol space.
(create_breakpoint): Adjust.
(expand_line_sal_maybe): Expand comment to mention symbol spaces.
Switch thread and symbol space when reading memory.
(parse_breakpoint_sals): Set the symbol space in the sal.
(break_command_really): Ditto.
(skip_prologue_sal): Switch and space.
(resolve_sal_pc): Ditto.
(watch_command_1): Record the symbol space in the sal.
(create_ada_exception_breakpoint): Adjust.
(clear_command): Adjust. Match symbol spaces.
(update_global_location_list): Use breakpoint_address_match.
(breakpoint_re_set_one): Switch thread and space.
(breakpoint_re_set): Save symbol space.
(breakpoint_re_set_thread): Also reset the symbol space.
(deprecated_insert_raw_breakpoint): Add an address space argument.
Adjust.
(insert_single_step_breakpoint): Ditto.
(single_step_breakpoint_inserted_here_p): Ditto.
* exec.h: Include "symspace.h".
(exec_bfd, exec_bfd_mtime): New defines.
(exec_close_1): Declare.
* exec.c: Include "gdbthread.h" and "symspace.h".
(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
(using_exec_ops): New.
(exec_close_1): Make public.
(exec_close): Add description. Remove target sections and close
executables from all symbol spaces.
(exec_file_attach): Add comment.
(add_target_sections): Check on `using_exec_ops' to check if the
target should be pushed.
(remove_target_sections): Only unpush the target if there are no
more target sections in any symbol space.
* gdbcore.h: Include "exec.h".
(exec_bfd, exec_bfd_mtime): Remove declarations.
* frame.h (get_frame_symbol_space, get_frame_address_space)
(frame_unwind_symbol_space): Declare.
* frame.c (struct frame_info) <sspace, aspace>: New fields.
(create_sentinel_frame): Add symbol space argument. Set the
sspace and aspace fields of the frame object.
(get_current_frame, create_new_frame): Adjust.
(get_frame_symbol_space): New.
(frame_unwind_symbol_space): New.
(get_frame_address_space): New.
* stack.c (print_frame_info): Adjust.
(print_frame): Use the frame's symbol space.
* gdbthread.h (any_live_thread_of_process): Declare.
* thread.c (any_live_thread_of_process): New.
(switch_to_thread): Switch the symbol space as well.
(restore_selected_frame): Don't warn if trying to restore frame
level 0.
* inferior.h: Include "symspace.h".
(detach_fork): Declare.
(struct inferior) <aspace, sspace, vfork_parent, vfork_child>
<pending_detach, waiting_for_vfork_done>: New fields.
(find_inferior_pid): Typo.
(find_inferior_id, find_inferior_for_symbol_space): Declare.
(inferior_list): Declare.
* inferior.c: Include "exec.h".
(inferior_list): Make public.
(delete_inferior_1): Always delete thread silently.
(find_inferior_id): Make public.
(find_inferior_for_symbol_space): New.
(print_inferior): Add symbol space and executable columns. Print
vfork parent/child relationships.
* objfiles.h: Include "symspace.h".
(struct objfile) <sspace>: New field.
(symfile_objfile, object_files): Don't declare.
(ALL_SSPACE_OBJFILES): New.
(ALL_SSPACE_OBJFILES_SAFE): New.
(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
(ALL_SSPACE_SYMTABS): New.
(ALL_PRIMARY_SYMTABS): Adjust.
(ALL_SSPACE_PRIMARY_SYMTABS): New.
(ALL_PSYMTABS): Adjust.
(ALL_SSPACE_PSYMTABS): New.
* objfiles.c (object_files, symfile_objfile): Delete.
(struct objfile_sspace_info): New.
(objfiles_sspace_data): New.
(objfiles_sspace_data_cleanup): New.
(get_objfile_sspace_data): New.
(objfiles_changed_p): Delete.
(allocate_objfile): Set the objfile's symbol space. Adjust to
reference objfiles_changed_p in sspace data.
(free_objfile): Adjust to reference objfiles_changed_p in sspace
data.
(objfile_relocate): Ditto.
(update_section_map): Add sspace argument. Adjust to iterate over
objfiles in the passed in sspace.
(find_pc_section): Delete sections and num_sections statics.
Adjust to refer to symbol space's objfiles_changed_p. Adjust to
refer to sections and num_sections store in the objfile's sspace
data.
(objfiles_changed): Adjust to reference objfiles_changed_p in
sspace data.
(_initialize_objfiles): New.
* linespec.c (decode_all_digits, decode_dollar): Set the sal's
symbol space.
* source.c (current_source_sspace): New.
(get_current_source_symtab_and_line): Set the sal's symbol space.
(set_current_source_symtab_and_line): Set current_source_sspace.
(select_source_symtab): Ditto. Use ALL_OBJFILES.
(forget_cached_source_info): Iterate over all symbol spaces.
* symfile.c (clear_symtab_users): Adjust.
* symmisc.c (print_symbol_bcache_statistics): Iterate over all
symbol spaces.
(print_objfile_statistics): Ditto.
(maintenance_print_msymbols): Ditto.
(maintenance_print_objfiles): Ditto.
(maintenance_info_symtabs): Ditto.
(maintenance_info_psymtabs): Ditto.
* symtab.h (SYMTAB_SSPACE): New.
(struct symtab_and_line) <sspace>: New field.
* symtab.c (init_sal): Clear the sal's symbol space.
(find_pc_sect_symtab): Set the sal's symbol space. Switch thread
and space.
(append_expanded_sal): Add symbol space argument. Iterate over
all symbol spaces.
(expand_line_sal): Iterate over all symbol spaces. Switch symbol
space.
* target.h (enum target_waitkind) <TARGET_WAITKIND_VFORK_DONE>: New.
(struct target_ops) <to_thread_address_space>: New field.
(target_thread_address_space): Define.
* target.c (target_detach): Only remove breakpoints from the
inferior we're detaching.
(target_thread_address_space): New.
* defs.h (initialize_symspace): Declare.
* top.c (gdb_init): Call it.
* solist.h (struct so_list) <sspace>: New field.
* solib.h (struct symbol_space): Forward declare.
(solib_name_from_address): Adjust prototype.
* solib.c (so_list_head): Replace with a macro referencing the
symbol space.
(update_solib_list): Set the so's symbol space.
(solib_name_from_address): Add a symbol space argument and adjust.
* solib-svr4.c (struct svr4_info) <pid>: Delete field.
<interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low>
<interp_plt_sect_high>: New fields.
(svr4_info_p, svr4_info): Delete.
(solib_svr4_sspace_data): New.
(get_svr4_info): Rewrite.
(svr4_sspace_data_cleanup): New.
(open_symbol_file_object): Adjust.
(svr4_default_sos): Adjust.
(svr4_fetch_objfile_link_map): Adjust.
(interp_text_sect_low, interp_text_sect_high, interp_plt_sect_low)
(interp_plt_sect_high): Delete.
(svr4_in_dynsym_resolve_code): Adjust.
(enable_break): Adjust.
(svr4_clear_solib): Revert bit that removed the svr4_info here,
and reinstate clearing debug_base, debug_loader_offset_p,
debug_loader_offset and debug_loader_name.
(_initialize_svr4_solib): Register solib_svr4_sspace_data. Don't
install an inferior_exit observer anymore.
* printcmd.c (struct display) <sspace>: New field.
(display_command): Set the display's sspace.
(do_one_display): Match the display's sspace.
(display_uses_solib_p): Ditto.
* linux-fork.c (detach_fork): Moved to infrun.c.
(_initialize_linux_fork): Moved "detach-on-fork" command to
infrun.c.
* infrun.c (detach_fork): Moved from linux-fork.c.
(proceed_after_vfork_done): New.
(handle_vfork_child_exec_or_exit): New.
(follow_exec_mode_replace, follow_exec_mode_keep)
(follow_exec_mode_names, follow_exec_mode_string)
(show_follow_exec_mode_string): New.
(follow_exec): New. Reinstate the mark_breakpoints_out call.
Remove shared libraries before attaching new executable. If user
wants to keep the symbol space, keep it.
(displaced_step_fixup): Adjust to pass an address space to the
breakpoints module.
(resume): Ditto.
(clear_proceed_status): In all-stop mode, always clear the proceed
status of all threads.
(prepare_to_proceed): Adjust to pass an address space to the
breakpoints module.
(proceed): Ditto.
(adjust_pc_after_break): Ditto.
(handle_inferior_event): When handling a process exit, switch the
symbol space to the inferior's that had exited. Call
handle_vfork_child_exec_or_exit. Adjust to pass an address space
to the breakpoints module. In non-stop mode, when following a
fork and detach-fork is off, also resume the other branch. Handle
TARGET_WAITKIND_VFORK_DONE. Set the symbol space in sals.
(normal_stop): Prune symbol spaces.
(_initialize_infrun): Install the new "follow-exec-mode" command.
"detach-on-fork" moved here.
* regcache.h (get_regcache_aspace): Declare.
* regcache.c (struct regcache) <aspace>: New field.
(regcache_xmalloc): Clear the aspace.
(get_regcache_aspace): New.
(regcache_cpy): Copy the aspace field.
(regcache_cpy_no_passthrough): Ditto.
(get_thread_regcache): Fetch the thread's address space from the
target, and store it in the regcache.
* infcall.c (call_function_by_hand): Set the sal's sspace.
* arch-utils.c (default_has_shared_address_space): New.
* arch-utils.h (default_has_shared_address_space): Declare.
* gdbarch.sh (has_shared_address_space): New.
* gdbarch.h, gdbarch.c: Regenerate.
* linux-tdep.c: Include auxv.h, target.h, elf/common.h.
(linux_has_shared_address_space): New.
(_initialize_linux_tdep): Declare.
* arm-tdep.c (arm_software_single_step): Pass the frame's address
space to insert_single_step_breakpoint.
* arm-linux-tdep.c (arm_linux_software_single_step): Pass the
frame's sspace to breakpoint functions.
* cris-tdep.c (crisv32_single_step_through_delay): Ditto.
(cris_software_single_step): Ditto.
* mips-tdep.c (deal_with_atomic_sequence): Add frame argument.
Pass the frame's sspace to breakpoint functions.
(mips_software_single_step): Adjust.
(mips_single_step_through_delay): Adjust.
* rs6000-aix-tdep.c (rs6000_software_single_step): Adjust.
* rs6000-tdep.c (ppc_deal_with_atomic_sequence): Adjust.
* solib-irix.c (enable_break): Adjust to pass the current frame's
address space to breakpoint functions.
* sparc-tdep.c (sparc_software_single_step): Ditto.
* spu-tdep.c (spu_software_single_step): Ditto.
* alpha-tdep.c (alpha_software_single_step): Ditto.
* record.c (record_wait): Adjust to pass an address space to the
breakpoints module.
* fork-child.c (fork_inferior): Set the new inferior's symbol and
address spaces.
* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's symbol
and address spaces.
(inf_ptrace_attach): Set the inferior's symbol and address spaces.
* linux-nat.c: Include "solib.h".
(linux_child_follow_fork): Manage parent and child's symbol and
address spaces. Clone the parent's ssymbol space is necessary.
Don't wait for the vfork to be done here. Refuse to resume if
following the vfork parent while leaving the child stopped.
(resume_callback): Don't resume a vfork parent.
(linux_nat_resume): Also check for pending events in the
lp->waitstatus field.
(linux_handle_extended_wait): Report TARGET_WAITKIND_VFORK_DONE
events to the core.
(stop_wait_callback): Don't wait for SIGSTOP on vfork parents.
(cancel_breakpoint): Adjust.
* linux-thread-db.c (thread_db_wait): Don't remove thread event
breakpoints here.
(thread_db_mourn_inferior): Don't mark breakpoints out here.
Remove thread event breakpoints after mourning.
* corelow.c: Include symspace.h.
(core_open): Set the inferior's symbol and address spaces.
* remote.c (remote_add_inferior): Set the new inferior's symbol
and address spaces.
(remote_start_remote): Update address spaces.
(extended_remote_create_inferior_1): Don't init the thread list if
we already debugging other inferiors.
* darwin-nat.c (darwin_attach): Set the new inferior's symbol and
address spaces.
* gnu-nat.c (gnu_attach): Ditto.
* go32-nat.c (go32_create_inferior): Ditto.
* inf-ttrace.c (inf_ttrace_follow_fork, inf_ttrace_attach): Ditto.
* monitor.c (monitor_open): Ditto.
* nto-procfs.c (procfs_attach, procfs_create_inferior): Ditto.
* procfs.c (do_attach): Ditto.
* windows-nat.c (do_initial_windows_stuff): Ditto.
* tui/tui-disasm.c: Include "symspace.h".
(tui_set_disassem_content): Pass an address space to
breakpoint_here_p.
* NEWS: Mention multi-program, or multi-exec debugging support.
Mention new commands "info symbol-spaces", "symbol-space",
"add-symbol-space", "clone-symbol-space", "remove-symbol-space",
and new option "set follow-exec-mode".
2009-09-03 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
gdb/testsuite/
* gdb.base/foll-vfork.exp: Adjust to spell out "follow-fork".
* gdb.base/foll-exec.exp: Adjust to expect a process id before
"Executing new program".
* gdb.base/foll-fork.exp: Adjust to spell out "follow-fork".
* gdb.base/multi-forks.exp: Ditto.
* gdb.base/attach.exp: Adjust to spell out "symbol-file".
* gdb.base/maint.exp: Adjust test.
* Makefile.in (ALL_SUBDIRS): Add gdb.multi.
* gdb.multi/Makefile.in: New.
* gdb.multi/base.exp: New.
* gdb.multi/goodbye.c: New.
* gdb.multi/hangout.c: New.
* gdb.multi/hello.c: New.
* gdb.multi/bkpt-multi-exec.c: New.
* gdb.multi/bkpt-multi-exec.exp: New.
* gdb.multi/crashme.c: New.
2009-09-03 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
gdb/doc/
* gdb.texinfo (Multiple Programs): New node.
(Process): Rename node to...
(Forks): ... this. Document "set|show follow-exec-mode". Add
"info inferiors" example showing vfork parent/child relationships.
(Inferiors) <info inferiors>: Mention the new 'SSpace' and 'Main
Program' columns. Update example. Mention possible extra output
below each inferior line.
---
gdb/Makefile.in | 4
gdb/NEWS | 41 +
gdb/alpha-tdep.c | 3
gdb/arch-utils.c | 8
gdb/arch-utils.h | 2
gdb/arm-linux-tdep.c | 3
gdb/arm-tdep.c | 3
gdb/breakpoint.c | 589 ++++++++++++++----
gdb/breakpoint.h | 45 +
gdb/corelow.c | 6
gdb/cris-tdep.c | 8
gdb/darwin-nat.c | 2
gdb/defs.h | 4
gdb/doc/gdb.texinfo | 267 ++++++++
gdb/exec.c | 70 +-
gdb/exec.h | 5
gdb/fork-child.c | 6
gdb/frame.c | 46 +
gdb/frame.h | 9
gdb/gdbarch.c | 24
gdb/gdbarch.h | 6
gdb/gdbarch.sh | 3
gdb/gdbcore.h | 7
gdb/gdbthread.h | 4
gdb/gnu-nat.c | 2
gdb/go32-nat.c | 5
gdb/inf-ptrace.c | 4
gdb/inf-ttrace.c | 4
gdb/infcall.c | 1
gdb/inferior.c | 54 +
gdb/inferior.h | 43 +
gdb/infrun.c | 384 +++++++++++-
gdb/linespec.c | 4
gdb/linux-fork.c | 11
gdb/linux-nat.c | 291 ++++++---
gdb/linux-tdep.c | 22
gdb/linux-thread-db.c | 18
gdb/mips-tdep.c | 12
gdb/monitor.c | 5
gdb/nto-procfs.c | 4
gdb/objfiles.c | 123 ++-
gdb/objfiles.h | 67 +-
gdb/printcmd.c | 26
gdb/procfs.c | 2
gdb/record.c | 19
gdb/regcache.c | 20
gdb/regcache.h | 5
gdb/remote.c | 34 -
gdb/rs6000-aix-tdep.c | 3
gdb/rs6000-tdep.c | 3
gdb/solib-irix.c | 6
gdb/solib-svr4.c | 155 ++--
gdb/solib.c | 12
gdb/solib.h | 3
gdb/solist.h | 3
gdb/source.c | 30
gdb/sparc-tdep.c | 5
gdb/spu-tdep.c | 6
gdb/stack.c | 6
gdb/symfile.c | 2
gdb/symmisc.c | 32 -
gdb/symspace.c | 892 ++++++++++++++++++++++++++++
gdb/symspace.h | 288 +++++++++
gdb/symtab.c | 64 +-
gdb/symtab.h | 5
gdb/target.c | 23
gdb/target.h | 13
gdb/testsuite/Makefile.in | 2
gdb/testsuite/gdb.base/attach.exp | 2
gdb/testsuite/gdb.base/foll-exec.exp | 10
gdb/testsuite/gdb.base/foll-fork.exp | 102 +--
gdb/testsuite/gdb.base/foll-vfork.exp | 40 -
gdb/testsuite/gdb.base/maint.exp | 4
gdb/testsuite/gdb.base/multi-forks.exp | 4
gdb/testsuite/gdb.multi/Makefile.in | 14
gdb/testsuite/gdb.multi/base.exp | 102 +++
gdb/testsuite/gdb.multi/bkpt-multi-exec.c | 13
gdb/testsuite/gdb.multi/bkpt-multi-exec.exp | 84 ++
gdb/testsuite/gdb.multi/crashme.c | 12
gdb/testsuite/gdb.multi/goodbye.c | 62 +
gdb/testsuite/gdb.multi/hangout.c | 26
gdb/testsuite/gdb.multi/hello.c | 46 +
gdb/thread.c | 27
gdb/top.c | 6
gdb/tui/tui-disasm.c | 4
gdb/windows-nat.c | 2
86 files changed, 3803 insertions(+), 635 deletions(-)
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/Makefile.in 2009-09-03 03:02:39.000000000 +0100
@@ -664,7 +664,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
serial.c ser-base.c ser-unix.c \
solib.c solib-null.c source.c \
stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
- symtab.c \
+ symspace.c symtab.c \
target.c target-descriptions.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
@@ -783,7 +783,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
blockframe.o breakpoint.o findvar.o regcache.o \
charset.o disasm.o dummy-frame.o dfp.o \
source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
- block.o symtab.o symfile.o symmisc.o linespec.o dictionary.o \
+ block.o symspace.o symtab.o symfile.o symmisc.o linespec.o dictionary.o \
infcall.o \
infcmd.o infrun.o \
expprint.o environ.o stack.o thread.o \
Index: src/gdb/symspace.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/symspace.h 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,288 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef SYMSPACE_H
+#define SYMSPACE_H
+
+#include "target.h"
+#include "vec.h"
+
+struct target_ops;
+struct bfd;
+struct objfile;
+struct inferior;
+struct exec;
+struct address_space;
+struct symbol_space_data;
+
+/* A symbol space represents a symbolic view of an address space.
+ Roughly speaking, it holds all the data associated with a
+ non-running-yet program (main executable, main symbols), and when
+ an inferior is running and is bound to it, includes the list of its
+ mapped in shared libraries.
+
+ In the traditional debugging scenario, there's a 1-1 correspondence
+ among symbol spaces, inferiors and address spaces, like so:
+
+ sspace1 (prog1) <--> inf1(pid1) <--> aspace1
+
+ In the case of debugging more than one traditional unix process or
+ program, we still have:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |----------------------------------------|
+ | sspace2 (prog1) | no inf yet | aspace2 |
+ |-----------------+------------+---------|
+ | sspace3 (prog2) | inf2(pid2) | aspace3 |
+ |-----------------+------------+---------|
+
+ In the former example, if inf1 forks (and GDB stays attached to
+ both processes), the new child will have its own symbol and address
+ spaces. Like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ However, had inf1 from the latter case vforked instead, it would
+ share the symbol and address spaces with its parent, until it execs
+ or exits, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ | | inf2(pid2) | |
+ |-----------------+------------+---------|
+
+ When the vfork child execs, it is finally given new symbol and
+ address spaces.
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | aspace1 |
+ |-----------------+------------+---------|
+ | sspace2 (prog1) | inf2(pid2) | aspace2 |
+ |-----------------+------------+---------|
+
+ There are targets where the OS (if any) doesn't provide memory
+ management or VM protection, where all inferiors share the same
+ address space --- e.g. uClinux. GDB models by having all inferiors
+ share the same address space, but, giving each its own symbol
+ space, like so:
+
+ |-----------------+------------+---------|
+ | sspace1 (prog1) | inf1(pid1) | |
+ |-----------------+------------+ |
+ | sspace2 (prog1) | inf2(pid2) | aspace1 |
+ |-----------------+------------+ |
+ | sspace3 (prog2) | inf3(pid3) | |
+ |-----------------+------------+---------|
+
+ The address space sharing matters for run control and breakpoints
+ management. E.g., did we just hit a known breakpoint that we need
+ to step over? Is this breakpoint a duplicate of this other one, or
+ do I need to insert a trap?
+
+ Then, there are targets where all symbols look the same for all
+ inferiors, although each has its own address space, as e.g.,
+ Ericsson DICOS. In such case, the model is:
+
+ |---------+------------+---------|
+ | | inf1(pid1) | aspace1 |
+ | +------------+---------|
+ | sspace | inf2(pid2) | aspace2 |
+ | +------------+---------|
+ | | inf3(pid3) | aspace3 |
+ |---------+------------+---------|
+
+ Note however, that the DICOS debug API takes care of making GDB
+ believe that breakpoints are "global". That is, although each
+ process does have its own private copy of data symbols (just like a
+ bunch of forks), to the breakpoints module, all processes share a
+ single address space, so all breakpoints set at the same address
+ are duplicates of each other, even breakpoints set in the data
+ space (e.g., call dummy breakpoints placed on stack). This allows
+ a simplification in the spaces implementation: we avoid caring for
+ a many-many links between address and symbol spaces. Either
+ there's a single address space bound to the symbol space
+ (traditional unix/uClinux), or, in the DICOS case, the address
+ space bound to the symbol space is mostly ignored. */
+
+/* The symbol space structure. */
+
+struct symbol_space
+ {
+ /* Pointer to next in linked list. */
+ struct symbol_space *next;
+
+ /* Unique ID number. */
+ int num;
+
+ /* The main executable loaded into this symbol space. This is
+ managed by the exec target. */
+
+ /* The BFD handle for the main executable. */
+ bfd *ebfd;
+ /* The last-modified time, from when the exec was brought in. */
+ long ebfd_mtime;
+
+ /* The address space attached to this symbol space. More than one
+ symbol space may be bound to the same address space. In the
+ traditional unix-like debugging scenario, this will usually
+ match the address space bound to the inferior, and is mostly
+ used by the breakpoints module for address matches. If the
+ target shares a symbol space for all inferiors and breakpoints
+ are global, then this field is ignored (we don't currently
+ support inferiors sharing a symbol space if the target doesn't
+ make breakpoints global). */
+ struct address_space *aspace;
+
+ /* True if this symbol space's section offsets don't yet represent
+ the final offsets of the "live" address space (that is, the
+ section addresses still require the relocation offsets to be
+ applied, and hence we can't trust the section addresses for
+ anything that pokes at live memory). E.g., for qOffsets
+ targets, or for PIE executables, until we connect and ask the
+ target for the final relocation offsets, the symbols we've used
+ to set breakpoints point at the wrong addresses. */
+ int executing_startup;
+
+ /* The object file that the main symbol table was loaded from
+ (e.g. the argument to the "symbol-file" or "file" command). */
+ struct objfile *symfile_object_file;
+
+ /* All known objfiles are kept in a linked list. This points to
+ the root of this list. */
+ struct objfile *objfiles;
+
+ /* The set of target sections matching the sections mapped into
+ this symbol space. Managed by both exec_ops and solib.c. */
+ struct target_section_table target_sections;
+
+ /* List of shared objects mapped into this space. Managed by
+ solib.c. */
+ struct so_list *so_list;
+
+ /* True if this was an auto-created sspace, e.g. created from
+ following a fork/exec; false, if this sspace was manually added
+ by the user, and should not be pruned automatically. */
+ int removable;
+
+ /* Per sspace data-pointers required by other GDB modules. */
+ void **data;
+ unsigned num_data;
+ };
+
+/* The object file that the main symbol table was loaded from (e.g. the
+ argument to the "symbol-file" or "file" command). */
+
+#define symfile_objfile current_symbol_space->symfile_object_file
+
+/* All known objfiles are kept in a linked list. This points to the
+ root of this list. */
+#define object_files current_symbol_space->objfiles
+
+/* The set of target sections matching the sections mapped into the
+ current symbol address space. */
+#define current_target_sections (¤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-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,892 @@
+/* Symbol and address space management, for GDB, the GNU debugger.
+
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "solib.h"
+#include "gdbthread.h"
+
+/* The last symbol space number assigned. */
+int last_symbol_space_num = 0;
+
+/* The head of the symbol spaces list. */
+struct symbol_space *symbol_spaces;
+
+/* Pointer to the current symbol space. */
+struct symbol_space *current_symbol_space;
+
+/* The last address space number assigned. */
+static int highest_address_space_num;
+
+/* Prototypes for local functions */
+
+static void symbol_space_alloc_data (struct symbol_space *);
+static void symbol_space_free_data (struct symbol_space *);
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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);
+}
+
+\f
+
+/* 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];
+}
+
+\f
+
+void
+initialize_symspace (void)
+{
+ add_info ("symbol-spaces", info_symbol_spaces_command, _("\
+Info about currently known symbol spaces."));
+ add_info_alias ("sspaces", "symbol-spaces", 0);
+
+ add_com ("symbol-space", no_class, symbol_space_command, _("\
+Change the current symbol space."));
+ add_com_alias ("sspace", "symbol-space", no_class, 0);
+
+ add_com ("add-symbol-space", no_class, add_symbol_space_command, _("\
+Add a new symbol space.\n\
+Usage: add-symbol-space [-copies <N>] [-exec <FILENAME>]\n\
+N is the optional number of spaces to add, default is 1.\n\
+FILENAME is the file name of the main executable to load\n\
+in the new symbol spaces."));
+
+ add_com ("remove-symbol-space", no_class, remove_symbol_space_command, _("\
+Remove symbol-space ID.\n\
+Usage: remove-symbol-space ID\n\
+Trying to remove the current symbol space, or a symbol space that\n\
+has bound inferiors is an error."));
+
+ add_com ("clone-symbol-space", no_class, clone_symbol_space_command, _("\
+Clone symbol space SPACE.\n\
+Usage: clone-symbol-space [-copies <N>] [ID]\n\
+Add N copies of symbol space ID. The new symbol space has the same\n\
+executable loaded as the original space. If -copies is not specified,\n\
+adds 1 copy. If ID is not specified, it is the current symbol space\n\
+that is cloned."));
+
+ /* There's always one symbol space. Note that this function isn't
+ an automatic _initialize_foo function, since other
+ _initialize_foo routine may need to install their per-sspace data
+ keys. We can only allocate a symspace when all those modules
+ have done that. Do this before initialize_current_architecture,
+ because that accesses exec_bfd. */
+ current_symbol_space = add_symbol_space (new_address_space ());
+}
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/breakpoint.h 2009-09-03 03:02:39.000000000 +0100
@@ -175,6 +175,9 @@ enum target_hw_bp_type
struct bp_target_info
{
+ /* Address space at which the breakpoint was placed. */
+ struct address_space *placed_address_space;
+
/* Address at which the breakpoint was placed. This is normally the
same as ADDRESS from the bp_location, except when adjustment
happens in gdbarch_breakpoint_from_pc. The most common form of
@@ -271,6 +274,14 @@ struct bp_location
different from the breakpoint architecture. */
struct gdbarch *gdbarch;
+ /* The symbol space associated with this breakpoint location
+ address. Note that an address space may be represented in more
+ than one symbol space (e.g. each uClinux program will be given
+ its own symbol space, but there will only be one address space
+ for all of them), but we must not insert more than one location
+ at the same address in the same address space. */
+ struct symbol_space *sspace;
+
/* Note that zero is a perfectly valid code address on some platforms
(for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
is not a special value for this field. Valid for all types except
@@ -405,6 +416,9 @@ struct breakpoint
equals this. */
struct frame_id frame_id;
+ /* The symbol space used to set the breakpoint. */
+ struct symbol_space *sspace;
+
/* String we used to set the breakpoint (malloc'd). */
char *addr_string;
/* Architecture we used to set the breakpoint. */
@@ -510,7 +524,8 @@ extern void bpstat_clear (bpstat *);
is part of the bpstat is copied as well. */
extern bpstat bpstat_copy (bpstat);
-extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid);
+extern bpstat bpstat_stop_status (struct address_space *aspace,
+ CORE_ADDR pc, ptid_t ptid);
\f
/* This bpstat_what stuff tells wait_for_inferior what to do with a
breakpoint (a challenging task). */
@@ -697,17 +712,17 @@ enum breakpoint_here
/* Prototypes for breakpoint-related functions. */
-extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
+extern enum breakpoint_here breakpoint_here_p (struct address_space *, CORE_ADDR);
-extern int moribund_breakpoint_here_p (CORE_ADDR);
+extern int moribund_breakpoint_here_p (struct address_space *, CORE_ADDR);
-extern int breakpoint_inserted_here_p (CORE_ADDR);
+extern int breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
-extern int regular_breakpoint_inserted_here_p (CORE_ADDR);
+extern int regular_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
-extern int software_breakpoint_inserted_here_p (CORE_ADDR);
+extern int software_breakpoint_inserted_here_p (struct address_space *, CORE_ADDR);
-extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
+extern int breakpoint_thread_match (struct address_space *, CORE_ADDR, ptid_t);
extern void until_break_command (char *, int, int);
@@ -725,7 +740,8 @@ extern struct breakpoint *clone_momentar
extern void set_ignore_count (int, int, int);
-extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
+extern void set_default_breakpoint (int, struct symbol_space *,
+ CORE_ADDR, struct symtab *, int);
extern void breakpoint_init_inferior (enum inf_context);
@@ -756,6 +772,8 @@ extern void insert_breakpoints (void);
extern int remove_breakpoints (void);
+extern int remove_breakpoints_pid (int pid);
+
/* This function can be used to physically insert eventpoints from the
specified traced inferior process, without modifying the breakpoint
package's state. This can be useful for those targets which support
@@ -791,6 +809,11 @@ extern void update_breakpoints_after_exe
inferior_ptid. */
extern int detach_breakpoints (int);
+/* This function is called when symbol space SSPACE is about to be
+ deleted. It takes care of updating breakpoints to not reference
+ this SSPACE anymore. */
+extern void breakpoint_symbol_space_exit (struct symbol_space *sspace);
+
extern void set_longjmp_breakpoint (int thread);
extern void delete_longjmp_breakpoint (int thread);
@@ -899,13 +922,15 @@ extern int remove_hw_watchpoints (void);
/* Manage a software single step breakpoint (or two). Insert may be called
twice before remove is called. */
-extern void insert_single_step_breakpoint (struct gdbarch *, CORE_ADDR);
+extern void insert_single_step_breakpoint (struct gdbarch *,
+ struct address_space *, CORE_ADDR);
extern void remove_single_step_breakpoints (void);
/* Manage manual breakpoints, separate from the normal chain of
breakpoints. These functions are used in murky target-specific
ways. Please do not add more uses! */
-extern void *deprecated_insert_raw_breakpoint (struct gdbarch *, CORE_ADDR);
+extern void *deprecated_insert_raw_breakpoint (struct gdbarch *,
+ struct address_space *, CORE_ADDR);
extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
/* Check if any hardware watchpoints have triggered, according to the
Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/breakpoint.c 2009-09-03 03:02:39.000000000 +0100
@@ -119,9 +119,15 @@ static CORE_ADDR adjust_breakpoint_addre
CORE_ADDR bpaddr,
enum bptype bptype);
-static void describe_other_breakpoints (struct gdbarch *, CORE_ADDR,
+static void describe_other_breakpoints (struct gdbarch *,
+ struct symbol_space *, CORE_ADDR,
struct obj_section *, int);
+static int breakpoint_address_match (struct address_space *aspace1,
+ CORE_ADDR addr1,
+ struct address_space *aspace2,
+ CORE_ADDR addr2);
+
static void breakpoints_info (char *, int);
static void breakpoint_1 (int, int);
@@ -148,6 +154,7 @@ typedef enum
insertion_state_t;
static int remove_breakpoint (struct bp_location *, insertion_state_t);
+static int remove_breakpoint_1 (struct bp_location *, insertion_state_t);
static enum print_stop_action print_it_typical (bpstat);
@@ -190,7 +197,8 @@ static void tcatch_command (char *arg, i
static void ep_skip_leading_whitespace (char **s);
-static int single_step_breakpoint_inserted_here_p (CORE_ADDR pc);
+static int single_step_breakpoint_inserted_here_p (struct address_space *,
+ CORE_ADDR pc);
static void free_bp_location (struct bp_location *loc);
@@ -320,9 +328,6 @@ static int executing_breakpoint_commands
/* Are overlay event breakpoints enabled? */
static int overlay_events_enabled;
-/* Are we executing startup code? */
-static int executing_startup;
-
/* Walk the following statement or block through all breakpoints.
ALL_BREAKPOINTS_SAFE does so even if the statment deletes the current
breakpoint. */
@@ -406,6 +411,8 @@ int default_breakpoint_valid;
CORE_ADDR default_breakpoint_address;
struct symtab *default_breakpoint_symtab;
int default_breakpoint_line;
+struct symbol_space *default_breakpoint_sspace;
+
\f
/* *PP is a string denoting a breakpoint. Get the number of the breakpoint.
Advance *PP after the string and any trailing whitespace.
@@ -754,6 +761,10 @@ breakpoint_restore_shadows (gdb_byte *bu
continue;
if (!b->inserted)
continue;
+ if (!breakpoint_address_match (b->target_info.placed_address_space, 0,
+ current_symbol_space->aspace, 0))
+ continue;
+
/* Addresses and length of the part of the breakpoint that
we need to copy. */
bp_addr = b->target_info.placed_address;
@@ -908,6 +919,7 @@ update_watchpoint (struct breakpoint *b,
struct frame_id saved_frame_id;
struct bp_location *loc;
bpstat bs;
+ struct symbol_space *frame_sspace;
/* We don't free locations. They are stored in bp_location_chain and
update_global_locations will eventually delete them and remove
@@ -936,6 +948,8 @@ update_watchpoint (struct breakpoint *b,
select_frame (fi);
}
+ frame_sspace = get_frame_symbol_space (get_selected_frame (NULL));
+
if (within_current_scope && reparse)
{
char *s;
@@ -1038,6 +1052,8 @@ update_watchpoint (struct breakpoint *b,
;
*tmp = loc;
loc->gdbarch = get_type_arch (value_type (v));
+
+ loc->sspace = frame_sspace;
loc->address = addr;
loc->length = len;
loc->watchpoint_type = type;
@@ -1117,6 +1133,7 @@ insert_bp_location (struct bp_location *
/* Initialize the target-specific information. */
memset (&bpt->target_info, 0, sizeof (bpt->target_info));
bpt->target_info.placed_address = bpt->address;
+ bpt->target_info.placed_address_space = bpt->sspace->aspace;
if (bpt->loc_type == bp_loc_software_breakpoint
|| bpt->loc_type == bp_loc_hardware_breakpoint)
@@ -1235,7 +1252,7 @@ Note: automatically using hardware break
if (val)
{
/* Can't set the breakpoint. */
- if (solib_name_from_address (bpt->address))
+ if (solib_name_from_address (bpt->sspace, bpt->address))
{
/* See also: disable_breakpoints_in_shlibs. */
val = 0;
@@ -1313,6 +1330,48 @@ Note: automatically using hardware break
return 0;
}
+/* This function is called when symbol space SSPACE is about to be
+ deleted. It takes care of updating breakpoints to not reference
+ SSPACE anymore. */
+
+void
+breakpoint_symbol_space_exit (struct symbol_space *sspace)
+{
+ struct breakpoint *b, *b_temp;
+ struct bp_location *loc, *loc_temp;
+
+ /* Remove any breakpoint that was set through this symbol space. */
+ ALL_BREAKPOINTS_SAFE (b, b_temp)
+ {
+ if (b->sspace == sspace)
+ delete_breakpoint (b);
+ }
+
+ /* Breakpoints set through other symbol spaces could have locations
+ bound to SSPACE as well. Remove those. */
+ ALL_BP_LOCATIONS_SAFE (loc, loc_temp)
+ {
+ struct bp_location *tmp;
+
+ if (loc->sspace == sspace)
+ {
+ if (loc->owner->loc == loc)
+ loc->owner->loc = loc->next;
+ else
+ for (tmp = loc->owner->loc; tmp->next != NULL; tmp = tmp->next)
+ if (tmp->next == loc)
+ {
+ tmp->next = loc->next;
+ break;
+ }
+ }
+ }
+
+ /* Now update the global location list to permanently delete the
+ removed locations above. */
+ update_global_location_list (0);
+}
+
/* Make sure all breakpoints are inserted in inferior.
Throws exception on any error.
A breakpoint that is already inserted won't be inserted
@@ -1356,9 +1415,14 @@ insert_breakpoint_locations (void)
/* Explicitly mark the warning -- this will only be printed if
there was an error. */
fprintf_unfiltered (tmp_error_stream, "Warning:\n");
-
+
+ save_current_space_and_thread ();
+
ALL_BP_LOCATIONS_SAFE (b, temp)
{
+ struct thread_info *tp;
+ CORE_ADDR last_addr;
+
if (!should_be_inserted (b) || b->inserted)
continue;
@@ -1368,6 +1432,35 @@ insert_breakpoint_locations (void)
&& !valid_thread_id (b->owner->thread))
continue;
+ switch_to_symbol_space_and_thread (b->sspace);
+
+ /* For targets that support global breakpoints, there's no need
+ to select an inferior to insert breakpoint to. In fact, even
+ if we aren't attached to any process yet, we should still
+ insert breakpoints. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch)
+ && ptid_equal (inferior_ptid, null_ptid))
+ continue;
+
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ struct inferior *inf = current_inferior ();
+ if (inf->waiting_for_vfork_done)
+ {
+ /* This is set when we're attached to the parent of the
+ vfork, and have detached from the child. The child
+ is running free, and we expect it to do an exec or
+ exit, at which point the OS makes the parent
+ schedulable again (and the target reports that the
+ vfork is done). Until the child is done with the
+ shared memory region, do not insert breakpoints in
+ parent, otherwise the child could still trip on the
+ parent's breakpoints. Since the parent is blocked
+ anyway, it won't miss any breakpoint. */
+ continue;
+ }
+ }
+
val = insert_bp_location (b, tmp_error_stream,
&disabled_breaks,
&hw_breakpoint_error);
@@ -1442,6 +1535,30 @@ remove_breakpoints (void)
return val;
}
+/* Remove breakpoints of process PID. */
+
+int
+remove_breakpoints_pid (int pid)
+{
+ struct bp_location *b;
+ int val;
+ struct inferior *inf = find_inferior_pid (pid);
+
+ ALL_BP_LOCATIONS (b)
+ {
+ if (b->sspace != inf->sspace)
+ continue;
+
+ if (b->inserted)
+ {
+ val = remove_breakpoint (b, mark_uninserted);
+ if (val != 0)
+ return val;
+ }
+ }
+ return 0;
+}
+
int
remove_hw_watchpoints (void)
{
@@ -1459,17 +1576,30 @@ remove_hw_watchpoints (void)
int
reattach_breakpoints (int pid)
{
+ struct cleanup *old_chain;
struct bp_location *b;
int val;
- struct cleanup *old_chain = save_inferior_ptid ();
struct ui_file *tmp_error_stream = mem_fileopen ();
int dummy1 = 0, dummy2 = 0;
+ struct inferior *inf;
+ struct thread_info *tp;
+
+ tp = any_live_thread_of_process (pid);
+ if (tp == NULL)
+ return 1;
+
+ inf = find_inferior_pid (pid);
+ old_chain = save_inferior_ptid ();
+
+ inferior_ptid = tp->ptid;
make_cleanup_ui_file_delete (tmp_error_stream);
- inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
+ if (b->sspace != inf->sspace)
+ continue;
+
if (b->inserted)
{
b->inserted = 0;
@@ -1499,6 +1629,7 @@ create_internal_breakpoint (struct gdbar
sal.pc = address;
sal.section = find_pc_overlay (sal.pc);
+ sal.sspace = current_symbol_space;
b = set_raw_breakpoint (gdbarch, sal, type);
b->number = internal_breakpoint_number--;
@@ -1543,8 +1674,13 @@ create_overlay_event_breakpoint (char *f
static void
create_longjmp_master_breakpoint (char *func_name)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
+ struct cleanup *old_chain;
+
+ old_chain = save_current_symbol_space ();
+ ALL_SSPACES (sspace)
ALL_OBJFILES (objfile)
{
struct breakpoint *b;
@@ -1553,6 +1689,8 @@ create_longjmp_master_breakpoint (char *
if (!gdbarch_get_longjmp_target_p (get_objfile_arch (objfile)))
continue;
+ set_current_symbol_space (sspace);
+
m = lookup_minimal_symbol_text (func_name, objfile);
if (m == NULL)
continue;
@@ -1564,6 +1702,8 @@ create_longjmp_master_breakpoint (char *
b->enable_state = bp_disabled;
}
update_global_location_list (1);
+
+ do_cleanups (old_chain);
}
void
@@ -1582,10 +1722,14 @@ update_breakpoints_after_exec (void)
here instead, because there may be other attempts to delete
breakpoints after detecting an exec and before reaching here. */
ALL_BP_LOCATIONS (bploc)
- gdb_assert (!bploc->inserted);
+ if (bploc->sspace == current_symbol_space)
+ gdb_assert (!bploc->inserted);
ALL_BREAKPOINTS_SAFE (b, temp)
{
+ if (b->sspace != current_symbol_space)
+ continue;
+
/* Solib breakpoints must be explicitly reset after an exec(). */
if (b->type == bp_shlib_event)
{
@@ -1687,25 +1831,36 @@ detach_breakpoints (int pid)
struct bp_location *b;
int val = 0;
struct cleanup *old_chain = save_inferior_ptid ();
+ struct inferior *inf = current_inferior ();
if (pid == PIDGET (inferior_ptid))
error (_("Cannot detach breakpoints of inferior_ptid"));
- /* Set inferior_ptid; remove_breakpoint uses this global. */
+ /* Set inferior_ptid; remove_breakpoint_1 uses this global. */
inferior_ptid = pid_to_ptid (pid);
ALL_BP_LOCATIONS (b)
{
+ if (b->sspace != inf->sspace)
+ continue;
+
if (b->inserted)
- val |= remove_breakpoint (b, mark_inserted);
+ val |= remove_breakpoint_1 (b, mark_inserted);
}
do_cleanups (old_chain);
return val;
}
+/* Remove the breakpoint location B from the current address space.
+ Note that this is used to detach breakpoints from a child fork.
+ When we get here, the child isn't in the inferior list, and neither
+ do we have objects to represent its address space --- we should
+ *not* look at b->sspace->aspace here. */
+
static int
-remove_breakpoint (struct bp_location *b, insertion_state_t is)
+remove_breakpoint_1 (struct bp_location *b, insertion_state_t is)
{
int val;
+ struct cleanup *old_chain;
if (b->owner->enable_state == bp_permanent)
/* Permanent breakpoints cannot be inserted or removed. */
@@ -1783,7 +1938,7 @@ remove_breakpoint (struct bp_location *b
/* In some cases, we might not be able to remove a breakpoint
in a shared library that has already been removed, but we
have not yet processed the shlib unload event. */
- if (val && solib_name_from_address (b->address))
+ if (val && solib_name_from_address (b->sspace, b->address))
val = 0;
if (val)
@@ -1819,6 +1974,30 @@ remove_breakpoint (struct bp_location *b
return 0;
}
+static int
+remove_breakpoint (struct bp_location *b, insertion_state_t is)
+{
+ int ret;
+ struct cleanup *old_chain;
+
+ if (b->owner->enable_state == bp_permanent)
+ /* Permanent breakpoints cannot be inserted or removed. */
+ return 0;
+
+ /* The type of none suggests that owner is actually deleted.
+ This should not ever happen. */
+ gdb_assert (b->owner->type != bp_none);
+
+ old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (b->sspace);
+
+ ret = remove_breakpoint_1 (b, is);
+
+ do_cleanups (old_chain);
+ return ret;
+}
+
/* Clear the "inserted" flag in all breakpoints. */
void
@@ -1827,7 +2006,8 @@ mark_breakpoints_out (void)
struct bp_location *bpt;
ALL_BP_LOCATIONS (bpt)
- bpt->inserted = 0;
+ if (bpt->sspace == current_symbol_space)
+ bpt->inserted = 0;
}
/* Clear the "inserted" flag in all breakpoints and delete any
@@ -1848,6 +2028,7 @@ breakpoint_init_inferior (enum inf_conte
struct breakpoint *b, *temp;
struct bp_location *bpt;
int ix;
+ struct symbol_space *sspace = current_symbol_space;
/* If breakpoint locations are shared across processes, then there's
nothing to do. */
@@ -1855,11 +2036,17 @@ breakpoint_init_inferior (enum inf_conte
return;
ALL_BP_LOCATIONS (bpt)
- if (bpt->owner->enable_state != bp_permanent)
+ {
+ if (bpt->sspace == sspace
+ && bpt->owner->enable_state != bp_permanent)
bpt->inserted = 0;
+ }
ALL_BREAKPOINTS_SAFE (b, temp)
{
+ if (b->loc && b->loc->sspace != sspace)
+ continue;
+
switch (b->type)
{
case bp_call_dummy:
@@ -1902,6 +2089,11 @@ breakpoint_init_inferior (enum inf_conte
VEC_free (bp_location_p, moribund_locations);
}
+/* These functions concerns about actual breakpoints inserted in the
+ target --- to e.g. check if we need to do decr_pc adjustment or if
+ we need to hop over the bkpt --- so we check for address space
+ match, not symbol space. */
+
/* breakpoint_here_p (PC) returns non-zero if an enabled breakpoint
exists at PC. It returns ordinary_breakpoint_here if it's an
ordinary breakpoint, or permanent_breakpoint_here if it's a
@@ -1913,7 +2105,7 @@ breakpoint_init_inferior (enum inf_conte
the target, to advance the PC past the breakpoint. */
enum breakpoint_here
-breakpoint_here_p (CORE_ADDR pc)
+breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;
int any_breakpoint_here = 0;
@@ -1926,7 +2118,8 @@ breakpoint_here_p (CORE_ADDR pc)
if ((breakpoint_enabled (bpt->owner)
|| bpt->owner->enable_state == bp_permanent)
- && bpt->address == pc) /* bp is enabled and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -1945,13 +2138,14 @@ breakpoint_here_p (CORE_ADDR pc)
/* Return true if there's a moribund breakpoint at PC. */
int
-moribund_breakpoint_here_p (CORE_ADDR pc)
+moribund_breakpoint_here_p (struct address_space *aspace, CORE_ADDR pc)
{
struct bp_location *loc;
int ix;
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
- if (loc->address == pc)
+ if (breakpoint_address_match (loc->sspace->aspace, loc->address,
+ aspace, pc))
return 1;
return 0;
@@ -1963,7 +2157,7 @@ moribund_breakpoint_here_p (CORE_ADDR pc
inserted and removed using direct target manipulation. */
int
-regular_breakpoint_inserted_here_p (CORE_ADDR pc)
+regular_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;
@@ -1974,7 +2168,8 @@ regular_breakpoint_inserted_here_p (CORE
continue;
if (bpt->inserted
- && bpt->address == pc) /* bp is inserted and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -1991,12 +2186,12 @@ regular_breakpoint_inserted_here_p (CORE
or a single step breakpoint inserted at PC. */
int
-breakpoint_inserted_here_p (CORE_ADDR pc)
+breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
- if (regular_breakpoint_inserted_here_p (pc))
+ if (regular_breakpoint_inserted_here_p (aspace, pc))
return 1;
- if (single_step_breakpoint_inserted_here_p (pc))
+ if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;
return 0;
@@ -2006,7 +2201,7 @@ breakpoint_inserted_here_p (CORE_ADDR pc
inserted at PC. */
int
-software_breakpoint_inserted_here_p (CORE_ADDR pc)
+software_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
const struct bp_location *bpt;
int any_breakpoint_here = 0;
@@ -2017,7 +2212,8 @@ software_breakpoint_inserted_here_p (COR
continue;
if (bpt->inserted
- && bpt->address == pc) /* bp is enabled and matches pc */
+ && breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
{
if (overlay_debugging
&& section_is_overlay (bpt->section)
@@ -2029,7 +2225,7 @@ software_breakpoint_inserted_here_p (COR
}
/* Also check for software single-step breakpoints. */
- if (single_step_breakpoint_inserted_here_p (pc))
+ if (single_step_breakpoint_inserted_here_p (aspace, pc))
return 1;
return 0;
@@ -2039,7 +2235,8 @@ software_breakpoint_inserted_here_p (COR
PC is valid for process/thread PTID. */
int
-breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
+breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
+ ptid_t ptid)
{
const struct bp_location *bpt;
/* The thread and task IDs associated to PTID, computed lazily. */
@@ -2056,7 +2253,8 @@ breakpoint_thread_match (CORE_ADDR pc, p
&& bpt->owner->enable_state != bp_permanent)
continue;
- if (bpt->address != pc)
+ if (!breakpoint_address_match (bpt->sspace->aspace, bpt->address,
+ aspace, pc))
continue;
if (bpt->owner->thread != -1)
@@ -2916,7 +3114,8 @@ which its expression is valid.\n");
breakpoint location BL. This function does not check if we
should stop, only if BL explains the stop. */
static int
-bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
+bpstat_check_location (const struct bp_location *bl,
+ struct address_space *aspace, CORE_ADDR bp_addr)
{
struct breakpoint *b = bl->owner;
@@ -2927,7 +3126,8 @@ bpstat_check_location (const struct bp_l
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catchpoint) /* a non-watchpoint bp */
{
- if (bl->address != bp_addr) /* address doesn't match */
+ if (!breakpoint_address_match (bl->sspace->aspace, bl->address,
+ aspace, bp_addr))
return 0;
if (overlay_debugging /* unmapped overlay section */
&& section_is_overlay (bl->section)
@@ -3151,7 +3351,8 @@ bpstat_check_breakpoint_conditions (bpst
commands, FIXME??? fields. */
bpstat
-bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
+bpstat_stop_status (struct address_space *aspace,
+ CORE_ADDR bp_addr, ptid_t ptid)
{
struct breakpoint *b = NULL;
const struct bp_location *bl;
@@ -3179,7 +3380,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
if (b->type == bp_hardware_watchpoint && bl != b->loc)
continue;
- if (!bpstat_check_location (bl, bp_addr))
+ if (!bpstat_check_location (bl, aspace, bp_addr))
continue;
/* Come here if it's a watchpoint, or if the break address matches */
@@ -3234,7 +3435,8 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
{
- if (loc->address == bp_addr)
+ if (breakpoint_address_match (loc->sspace->aspace, loc->address,
+ aspace, bp_addr))
{
bs = bpstat_alloc (loc, bs);
/* For hits of moribund locations, we should just proceed. */
@@ -3537,6 +3739,11 @@ static void print_breakpoint_location (s
char *wrap_indent,
struct ui_stream *stb)
{
+ struct cleanup *old_chain = save_current_symbol_space ();
+
+ if (loc != NULL)
+ set_current_symbol_space (loc->sspace);
+
if (b->source_file)
{
struct symbol *sym
@@ -3572,6 +3779,8 @@ static void print_breakpoint_location (s
print_address_symbolic (loc->address, stb->stream, demangle, "");
ui_out_field_stream (uiout, "at", stb);
}
+
+ do_cleanups (old_chain);
}
/* Print B to gdb_stdout. */
@@ -3580,7 +3789,8 @@ print_one_breakpoint_location (struct br
struct bp_location *loc,
int loc_number,
struct bp_location **last_loc,
- int print_address_bits)
+ int print_address_bits,
+ int allflag)
{
struct command_line *l;
struct symbol *sym;
@@ -3760,6 +3970,18 @@ print_one_breakpoint_location (struct br
break;
}
+ /* For backward compatibility, don't display sspaces unless there
+ are several. */
+ if (!header_of_multiple
+ && (number_of_symbol_spaces () > 1 || allflag))
+ {
+ if (loc)
+ {
+ ui_out_text (uiout, " sspace ");
+ ui_out_field_int (uiout, "sspace", loc->sspace->num);
+ }
+ }
+
if (!part_of_multiple)
{
if (b->thread != -1)
@@ -3893,9 +4115,10 @@ print_one_breakpoint_location (struct br
static void
print_one_breakpoint (struct breakpoint *b,
- struct bp_location **last_loc, int print_address_bits)
+ struct bp_location **last_loc, int print_address_bits,
+ int allflag)
{
- print_one_breakpoint_location (b, NULL, 0, last_loc, print_address_bits);
+ print_one_breakpoint_location (b, NULL, 0, last_loc, print_address_bits, allflag);
/* If this breakpoint has custom print function,
it's already printed. Otherwise, print individual
@@ -3919,7 +4142,7 @@ print_one_breakpoint (struct breakpoint
int n = 1;
for (loc = b->loc; loc; loc = loc->next, ++n)
print_one_breakpoint_location (b, loc, n, last_loc,
- print_address_bits);
+ print_address_bits, allflag);
}
}
}
@@ -3956,7 +4179,7 @@ do_captured_breakpoint_query (struct ui_
if (args->bnum == b->number)
{
int print_address_bits = breakpoint_address_bits (b);
- print_one_breakpoint (b, &dummy_loc, print_address_bits);
+ print_one_breakpoint (b, &dummy_loc, print_address_bits, 0);
return GDB_RC_OK;
}
}
@@ -4072,7 +4295,7 @@ breakpoint_1 (int bnum, int allflag)
/* We only print out user settable breakpoints unless the
allflag is set. */
if (allflag || user_settable_breakpoint (b))
- print_one_breakpoint (b, &last_loc, print_address_bits);
+ print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
do_cleanups (bkpttbl_chain);
@@ -4120,29 +4343,34 @@ maintenance_info_breakpoints (char *bnum
static int
breakpoint_has_pc (struct breakpoint *b,
+ struct symbol_space *sspace,
CORE_ADDR pc, struct obj_section *section)
{
struct bp_location *bl = b->loc;
for (; bl; bl = bl->next)
{
- if (bl->address == pc
+ if (bl->sspace == sspace
+ && bl->address == pc
&& (!overlay_debugging || bl->section == section))
return 1;
}
return 0;
}
-/* Print a message describing any breakpoints set at PC. */
+/* Print a message describing any breakpoints set at PC. This
+ concerns with logical breakpoints, so we match symbol spaces, not
+ address spaces. */
static void
-describe_other_breakpoints (struct gdbarch *gdbarch, CORE_ADDR pc,
+describe_other_breakpoints (struct gdbarch *gdbarch,
+ struct symbol_space *sspace, CORE_ADDR pc,
struct obj_section *section, int thread)
{
int others = 0;
struct breakpoint *b;
ALL_BREAKPOINTS (b)
- others += breakpoint_has_pc (b, pc, section);
+ others += breakpoint_has_pc (b, sspace, pc, section);
if (others > 0)
{
if (others == 1)
@@ -4150,7 +4378,7 @@ describe_other_breakpoints (struct gdbar
else /* if (others == ???) */
printf_filtered (_("Note: breakpoints "));
ALL_BREAKPOINTS (b)
- if (breakpoint_has_pc (b, pc, section))
+ if (breakpoint_has_pc (b, sspace, pc, section))
{
others--;
printf_filtered ("%d", b->number);
@@ -4179,10 +4407,12 @@ describe_other_breakpoints (struct gdbar
for the `break' command with no arguments. */
void
-set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
+set_default_breakpoint (int valid, struct symbol_space *sspace,
+ CORE_ADDR addr, struct symtab *symtab,
int line)
{
default_breakpoint_valid = valid;
+ default_breakpoint_sspace = sspace;
default_breakpoint_address = addr;
default_breakpoint_symtab = symtab;
default_breakpoint_line = line;
@@ -4216,6 +4446,20 @@ breakpoint_address_is_meaningful (struct
&& type != bp_catchpoint);
}
+/* Returns true if {ASPACE1,ADDR1} and {ASPACE2,ADDR2} represent the
+ same breakpoint location. In most targets, this is will be true if
+ ASPACE1 matches ASPACE2. On targets that have global breakpoints,
+ the address space doesn't really matter. */
+
+static int
+breakpoint_address_match (struct address_space *aspace1, CORE_ADDR addr1,
+ struct address_space *aspace2, CORE_ADDR addr2)
+{
+ return ((gdbarch_has_global_breakpoints (target_gdbarch)
+ || aspace1 == aspace2)
+ && addr1 == addr2);
+}
+
/* Rescan breakpoints at the same address and section as BPT,
marking the first one as "first" and any others as "duplicates".
This is so that the bpt instruction is only inserted once.
@@ -4223,7 +4467,9 @@ breakpoint_address_is_meaningful (struct
that one the official one, and the rest as duplicates. */
static void
-check_duplicates_for (CORE_ADDR address, struct obj_section *section)
+check_duplicates_for (struct address_space *aspace,
+ CORE_ADDR address,
+ struct obj_section *section)
{
struct bp_location *b;
int count = 0;
@@ -4235,9 +4481,10 @@ check_duplicates_for (CORE_ADDR address,
&& b->owner->enable_state != bp_startup_disabled
&& b->enabled
&& !b->shlib_disabled
- && b->address == address /* address / overlay match */
&& (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address))
{
/* Have we found a permanent breakpoint? */
if (b->owner->enable_state == bp_permanent)
@@ -4270,10 +4517,11 @@ check_duplicates_for (CORE_ADDR address,
&& b->owner->enable_state != bp_disabled
&& b->owner->enable_state != bp_call_disabled
&& b->owner->enable_state != bp_startup_disabled
- && b->enabled && !b->shlib_disabled
- && b->address == address /* address / overlay match */
- && (!overlay_debugging || b->section == section)
- && breakpoint_address_is_meaningful (b->owner))
+ && b->enabled && !b->shlib_disabled
+ && breakpoint_address_is_meaningful (b->owner)
+ && breakpoint_address_match (b->sspace->aspace, b->address,
+ aspace, address)
+ && (!overlay_debugging || b->section == section))
{
if (b->inserted)
internal_error (__FILE__, __LINE__,
@@ -4295,7 +4543,7 @@ check_duplicates (struct breakpoint *bpt
return;
for (; bl; bl = bl->next)
- check_duplicates_for (bl->address, bl->section);
+ check_duplicates_for (bl->sspace->aspace, bl->address, bl->section);
}
static void
@@ -4518,6 +4766,9 @@ set_raw_breakpoint (struct gdbarch *gdba
if (!loc_gdbarch)
loc_gdbarch = b->gdbarch;
+ if (bptype != bp_catchpoint)
+ gdb_assert (sal.sspace != NULL);
+
/* Adjust the breakpoint's address prior to allocating a location.
Once we call allocate_bp_location(), that mostly uninitialized
location will be placed on the location chain. Adjustment of the
@@ -4530,6 +4781,11 @@ set_raw_breakpoint (struct gdbarch *gdba
b->loc->gdbarch = loc_gdbarch;
b->loc->requested_address = sal.pc;
b->loc->address = adjusted_address;
+ b->loc->sspace = sal.sspace;
+
+ /* Store the symbol space that was used to set the breakpoint, for
+ breakpoint resetting. */
+ b->sspace = sal.sspace;
if (sal.symtab == NULL)
b->source_file = NULL;
@@ -4577,7 +4833,8 @@ set_longjmp_breakpoint (int thread)
longjmp "master" breakpoints. Here, we simply create momentary
clones of those and enable them for the requested thread. */
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_longjmp_master)
+ if (b->sspace == current_symbol_space
+ && b->type == bp_longjmp_master)
{
struct breakpoint *clone = clone_momentary_breakpoint (b);
clone->type = bp_longjmp;
@@ -4650,7 +4907,8 @@ remove_thread_event_breakpoints (void)
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_thread_event)
+ if (b->type == bp_thread_event
+ && b->loc->sspace == current_symbol_space)
delete_breakpoint (b);
}
@@ -4686,7 +4944,8 @@ remove_solib_event_breakpoints (void)
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_shlib_event)
+ if (b->type == bp_shlib_event
+ && b->loc->sspace == current_symbol_space)
delete_breakpoint (b);
}
@@ -4719,11 +4978,12 @@ disable_breakpoints_in_shlibs (void)
if (((b->type == bp_breakpoint)
|| (b->type == bp_hardware_breakpoint)
|| (b->type == bp_tracepoint))
+ && loc->sspace == current_symbol_space
&& !loc->shlib_disabled
#ifdef PC_SOLIB
&& PC_SOLIB (loc->address)
#else
- && solib_name_from_address (loc->address)
+ && solib_name_from_address (loc->sspace, loc->address)
#endif
)
{
@@ -4754,6 +5014,7 @@ disable_breakpoints_in_unloaded_shlib (s
struct breakpoint *b = loc->owner;
if ((loc->loc_type == bp_loc_hardware_breakpoint
|| loc->loc_type == bp_loc_software_breakpoint)
+ && solib->sspace == loc->sspace
&& !loc->shlib_disabled
&& (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)
&& solib_contains_address_p (solib, loc->address))
@@ -4957,6 +5218,7 @@ create_catchpoint (struct gdbarch *gdbar
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
+ sal.sspace = current_symbol_space;
b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
set_breakpoint_count (breakpoint_count + 1);
@@ -5138,6 +5400,9 @@ disable_breakpoints_before_startup (void
ALL_BREAKPOINTS (b)
{
+ if (b->sspace != current_symbol_space)
+ continue;
+
if ((b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint)
&& breakpoint_enabled (b))
@@ -5150,7 +5415,7 @@ disable_breakpoints_before_startup (void
if (found)
update_global_location_list (0);
- executing_startup = 1;
+ current_symbol_space->executing_startup = 1;
}
void
@@ -5159,10 +5424,13 @@ enable_breakpoints_after_startup (void)
struct breakpoint *b;
int found = 0;
- executing_startup = 0;
+ current_symbol_space->executing_startup = 0;
ALL_BREAKPOINTS (b)
{
+ if (b->sspace != current_symbol_space)
+ continue;
+
if ((b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint)
&& b->enable_state == bp_startup_disabled)
@@ -5227,6 +5495,7 @@ clone_momentary_breakpoint (struct break
copy->loc->requested_address = orig->loc->requested_address;
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
+ copy->loc->sspace = orig->loc->sspace;
if (orig->source_file == NULL)
copy->source_file = NULL;
@@ -5236,6 +5505,7 @@ clone_momentary_breakpoint (struct break
copy->line_number = orig->line_number;
copy->frame_id = orig->frame_id;
copy->thread = orig->thread;
+ copy->sspace = orig->sspace;
copy->enable_state = bp_enabled;
copy->disposition = disp_donttouch;
@@ -5418,6 +5688,8 @@ add_location_to_breakpoint (struct break
loc->requested_address = sal->pc;
loc->address = adjust_breakpoint_address (loc->gdbarch,
loc->requested_address, b->type);
+ loc->sspace = sal->sspace;
+ gdb_assert (loc->sspace != NULL);
loc->section = sal->section;
set_breakpoint_location_function (loc);
@@ -5452,7 +5724,10 @@ bp_loc_is_permanent (struct bp_location
/* Enable the automatic memory restoration from breakpoints while
we read the memory. Otherwise we could say about our temporary
breakpoints they are permanent. */
- cleanup = make_show_memory_breakpoints_cleanup (0);
+ cleanup = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (loc->sspace);
+ make_show_memory_breakpoints_cleanup (0);
if (target_read_memory (loc->address, target_mem, len) == 0
&& memcmp (target_mem, brk, len) == 0)
@@ -5492,6 +5767,8 @@ create_breakpoint (struct gdbarch *gdbar
error (_("Hardware breakpoints used exceeds limit."));
}
+ gdb_assert (sals.nelts > 0);
+
for (i = 0; i < sals.nelts; ++i)
{
struct symtab_and_line sal = sals.sals[i];
@@ -5504,7 +5781,7 @@ create_breakpoint (struct gdbarch *gdbar
loc_gdbarch = gdbarch;
describe_other_breakpoints (loc_gdbarch,
- sal.pc, sal.section, thread);
+ sal.sspace, sal.pc, sal.section, thread);
}
if (i == 0)
@@ -5520,7 +5797,9 @@ create_breakpoint (struct gdbarch *gdbar
b->enable_state = enabled ? bp_enabled : bp_disabled;
b->disposition = disposition;
- if (enabled && executing_startup
+ b->sspace = sals.sals[0].sspace;
+
+ if (enabled && b->sspace->executing_startup
&& (b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint))
b->enable_state = bp_startup_disabled;
@@ -5570,20 +5849,19 @@ remove_sal (struct symtabs_and_lines *sa
--(sal->nelts);
}
-/* If appropriate, obtains all sals that correspond
- to the same file and line as SAL. This is done
- only if SAL does not have explicit PC and has
- line and file information. If we got just a single
- expanded sal, return the original.
-
- Otherwise, if SAL.explicit_line is not set, filter out
- all sals for which the name of enclosing function
- is different from SAL. This makes sure that if we have
- breakpoint originally set in template instantiation, say
- foo<int>(), we won't expand SAL to locations at the same
- line in all existing instantiations of 'foo'.
+/* If appropriate, obtains all sals that correspond to the same file
+ and line as SAL, in all symbol spaces. Users debugging with IDEs,
+ will want to set a breakpoint at foo.c:line, and not really care
+ about symbol spaces. This is done only if SAL does not have
+ explicit PC and has line and file information. If we got just a
+ single expanded sal, return the original.
+
+ Otherwise, if SAL.explicit_line is not set, filter out all sals for
+ which the name of enclosing function is different from SAL. This
+ makes sure that if we have breakpoint originally set in template
+ instantiation, say foo<int>(), we won't expand SAL to locations at
+ the same line in all existing instantiations of 'foo'. */
-*/
static struct symtabs_and_lines
expand_line_sal_maybe (struct symtab_and_line sal)
{
@@ -5592,6 +5870,7 @@ expand_line_sal_maybe (struct symtab_and
char *original_function = NULL;
int found;
int i;
+ struct cleanup *old_chain;
/* If we have explicit pc, don't expand.
If we have no line number, we can't expand. */
@@ -5604,9 +5883,16 @@ expand_line_sal_maybe (struct symtab_and
}
sal.pc = 0;
+
+ old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (sal.sspace);
+
find_pc_partial_function (original_pc, &original_function, NULL, NULL);
-
+
+ /* Note that expand_line_sal visits *all* symbol spaces. */
expanded = expand_line_sal (sal);
+
if (expanded.nelts == 1)
{
/* We had one sal, we got one sal. Without futher
@@ -5616,6 +5902,7 @@ expand_line_sal_maybe (struct symtab_and
expanded.sals = xmalloc (sizeof (struct symtab_and_line));
sal.pc = original_pc;
expanded.sals[0] = sal;
+ do_cleanups (old_chain);
return expanded;
}
@@ -5626,6 +5913,11 @@ expand_line_sal_maybe (struct symtab_and
{
CORE_ADDR pc = expanded.sals[i].pc;
char *this_function;
+
+ /* We need to switch threads as well since we're about to
+ read memory. */
+ switch_to_symbol_space_and_thread (expanded.sals[i].sspace);
+
if (find_pc_partial_function (pc, &this_function,
&func_addr, &func_end))
{
@@ -5669,7 +5961,8 @@ expand_line_sal_maybe (struct symtab_and
}
}
-
+ do_cleanups (old_chain);
+
if (expanded.nelts <= 1)
{
/* This is un ugly workaround. If we get zero
@@ -5761,6 +6054,7 @@ parse_breakpoint_sals (char **address,
sal.pc = default_breakpoint_address;
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
+ sal.sspace = default_breakpoint_sspace;
sal.section = find_pc_overlay (sal.pc);
/* "break" without arguments is equivalent to "break *PC" where PC is
@@ -6079,8 +6373,9 @@ break_command_really (struct gdbarch *gd
b->condition_not_parsed = 1;
b->ops = ops;
b->enable_state = enabled ? bp_enabled : bp_disabled;
+ b->sspace = current_symbol_space;
- if (enabled && executing_startup
+ if (enabled && b->sspace->executing_startup
&& (b->type == bp_breakpoint
|| b->type == bp_hardware_breakpoint))
b->enable_state = bp_startup_disabled;
@@ -6153,19 +6448,25 @@ set_breakpoint (struct gdbarch *gdbarch,
static void
skip_prologue_sal (struct symtab_and_line *sal)
{
- struct symbol *sym = find_pc_function (sal->pc);
+ struct symbol *sym;
struct symtab_and_line start_sal;
+ struct cleanup *old_chain;
- if (sym == NULL)
- return;
+ old_chain = save_current_space_and_thread ();
- start_sal = find_function_start_sal (sym, 1);
- if (sal->pc < start_sal.pc)
+ sym = find_pc_function (sal->pc);
+ if (sym != NULL)
{
- start_sal.explicit_line = sal->explicit_line;
- start_sal.explicit_pc = sal->explicit_pc;
- *sal = start_sal;
+ start_sal = find_function_start_sal (sym, 1);
+ if (sal->pc < start_sal.pc)
+ {
+ start_sal.explicit_line = sal->explicit_line;
+ start_sal.explicit_pc = sal->explicit_pc;
+ *sal = start_sal;
+ }
}
+
+ do_cleanups (old_chain);
}
/* Helper function for break_command_1 and disassemble_command. */
@@ -6216,10 +6517,15 @@ resolve_sal_pc (struct symtab_and_line *
source). */
struct minimal_symbol *msym;
+ struct cleanup *old_chain = save_current_space_and_thread ();
+
+ switch_to_symbol_space_and_thread (sal->sspace);
msym = lookup_minimal_symbol_by_pc (sal->pc);
if (msym)
sal->section = SYMBOL_OBJ_SECTION (msym);
+
+ do_cleanups (old_chain);
}
}
}
@@ -6410,6 +6716,8 @@ watch_command_1 (char *arg, int accessfl
}
}
+ sal.sspace = current_symbol_space;
+
/* Parse the rest of the arguments. */
innermost_block = NULL;
exp_start = arg;
@@ -7093,7 +7401,8 @@ create_ada_exception_breakpoint (struct
if (!loc_gdbarch)
loc_gdbarch = gdbarch;
- describe_other_breakpoints (loc_gdbarch, sal.pc, sal.section, -1);
+ describe_other_breakpoints (loc_gdbarch,
+ sal.sspace, sal.pc, sal.section, -1);
/* FIXME: brobecker/2006-12-28: Actually, re-implement a special
version for exception catchpoints, because two catchpoints
used for different exception names will use the same address.
@@ -7210,6 +7519,7 @@ clear_command (char *arg, int from_tty)
sal.line = default_breakpoint_line;
sal.symtab = default_breakpoint_symtab;
sal.pc = default_breakpoint_address;
+ sal.sspace = default_breakpoint_sspace;
if (sal.symtab == 0)
error (_("No source file specified."));
@@ -7273,13 +7583,15 @@ clear_command (char *arg, int from_tty)
struct bp_location *loc = b->loc;
for (; loc; loc = loc->next)
{
- int pc_match = sal.pc
+ int pc_match = sal.pc
+ && (loc->sspace == sal.sspace)
&& (loc->address == sal.pc)
&& (!section_is_overlay (loc->section)
|| loc->section == sal.section);
int line_match = ((default_match || (0 == sal.pc))
&& b->source_file != NULL
&& sal.symtab != NULL
+ && sal.sspace == loc->sspace
&& strcmp (b->source_file, sal.symtab->filename) == 0
&& b->line_number == sal.line);
if (pc_match || line_match)
@@ -7448,8 +7760,12 @@ update_global_location_list (int should_
call to check_duplicates will fix up this later. */
loc2->duplicate = 0;
if (should_be_inserted (loc2)
- && loc2 != loc && loc2->address == loc->address)
- {
+ && loc2 != loc
+ && breakpoint_address_match (loc2->sspace->aspace,
+ loc2->address,
+ loc->sspace->aspace,
+ loc->address))
+ {
loc2->inserted = 1;
loc2->target_info = loc->target_info;
keep_in_target = 1;
@@ -7833,7 +8149,8 @@ update_breakpoint_locations (struct brea
if (have_ambiguous_names)
{
for (; l; l = l->next)
- if (e->address == l->address)
+ if (breakpoint_address_match (e->sspace->aspace, e->address,
+ l->sspace->aspace, l->address))
{
l->enabled = 0;
break;
@@ -7870,12 +8187,12 @@ breakpoint_re_set_one (void *bint)
int i;
int not_found = 0;
int *not_found_ptr = ¬_found;
- struct symtabs_and_lines sals = {};
- struct symtabs_and_lines expanded;
+ struct symtabs_and_lines sals = {0};
+ struct symtabs_and_lines expanded = {0};
char *s;
enum enable_state save_enable;
struct gdb_exception e;
- struct cleanup *cleanups;
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
switch (b->type)
{
@@ -7900,6 +8217,10 @@ breakpoint_re_set_one (void *bint)
set_language (b->language);
input_radix = b->input_radix;
s = b->addr_string;
+
+ save_current_space_and_thread ();
+ switch_to_symbol_space_and_thread (b->sspace);
+
TRY_CATCH (e, RETURN_MASK_ERROR)
{
sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL,
@@ -7933,29 +8254,31 @@ breakpoint_re_set_one (void *bint)
}
}
- if (not_found)
- break;
-
- gdb_assert (sals.nelts == 1);
- resolve_sal_pc (&sals.sals[0]);
- if (b->condition_not_parsed && s && s[0])
- {
- char *cond_string = 0;
- int thread = -1;
- int task = 0;
-
- find_condition_and_thread (s, sals.sals[0].pc,
- &cond_string, &thread, &task);
- if (cond_string)
- b->cond_string = cond_string;
- b->thread = thread;
- b->task = task;
- b->condition_not_parsed = 0;
+ if (!not_found)
+ {
+ gdb_assert (sals.nelts == 1);
+
+ resolve_sal_pc (&sals.sals[0]);
+ if (b->condition_not_parsed && s && s[0])
+ {
+ char *cond_string = 0;
+ int thread = -1;
+ int task = 0;
+
+ find_condition_and_thread (s, sals.sals[0].pc,
+ &cond_string, &thread, &task);
+ if (cond_string)
+ b->cond_string = cond_string;
+ b->thread = thread;
+ b->task = task;
+ b->condition_not_parsed = 0;
+ }
+
+ expanded = expand_line_sal_maybe (sals.sals[0]);
}
- expanded = expand_line_sal_maybe (sals.sals[0]);
- cleanups = make_cleanup (xfree, sals.sals);
+
+ make_cleanup (xfree, sals.sals);
update_breakpoint_locations (b, expanded);
- do_cleanups (cleanups);
break;
case bp_watchpoint:
@@ -8028,6 +8351,7 @@ breakpoint_re_set_one (void *bint)
break;
}
+ do_cleanups (cleanups);
return 0;
}
@@ -8038,9 +8362,12 @@ breakpoint_re_set (void)
struct breakpoint *b, *temp;
enum language save_language;
int save_input_radix;
+ struct cleanup *old_chain;
save_language = current_language->la_language;
save_input_radix = input_radix;
+ old_chain = save_current_symbol_space ();
+
ALL_BREAKPOINTS_SAFE (b, temp)
{
/* Format possible error msg */
@@ -8055,6 +8382,8 @@ breakpoint_re_set (void)
jit_breakpoint_re_set ();
+ do_cleanups (old_chain);
+
create_overlay_event_breakpoint ("_ovly_debug_event");
create_longjmp_master_breakpoint ("longjmp");
create_longjmp_master_breakpoint ("_longjmp");
@@ -8073,6 +8402,12 @@ breakpoint_re_set_thread (struct breakpo
{
if (in_thread_list (inferior_ptid))
b->thread = pid_to_thread_id (inferior_ptid);
+
+ /* We're being called after following a fork. The new fork is
+ selected as current, and unless this was a vfork will have a
+ different symbol space from the original thread. Reset that
+ as well. */
+ b->loc->sspace = current_symbol_space;
}
}
@@ -8443,14 +8778,16 @@ decode_line_spec_1 (char *string, int fu
someday. */
void *
-deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
+deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch,
+ struct address_space *aspace, CORE_ADDR pc)
{
struct bp_target_info *bp_tgt;
- bp_tgt = xmalloc (sizeof (struct bp_target_info));
- memset (bp_tgt, 0, sizeof (struct bp_target_info));
+ bp_tgt = XZALLOC (struct bp_target_info);
+ bp_tgt->placed_address_space = aspace;
bp_tgt->placed_address = pc;
+
if (target_insert_breakpoint (gdbarch, bp_tgt) != 0)
{
/* Could not insert the breakpoint. */
@@ -8483,7 +8820,8 @@ static struct gdbarch *single_step_gdbar
/* Create and insert a breakpoint for software single step. */
void
-insert_single_step_breakpoint (struct gdbarch *gdbarch, CORE_ADDR next_pc)
+insert_single_step_breakpoint (struct gdbarch *gdbarch,
+ struct address_space *aspace, CORE_ADDR next_pc)
{
void **bpt_p;
@@ -8506,7 +8844,7 @@ insert_single_step_breakpoint (struct gd
corresponding changes elsewhere where single step breakpoints are
handled, however. So, for now, we use this. */
- *bpt_p = deprecated_insert_raw_breakpoint (gdbarch, next_pc);
+ *bpt_p = deprecated_insert_raw_breakpoint (gdbarch, aspace, next_pc);
if (*bpt_p == NULL)
error (_("Could not insert single-step breakpoint at %s"),
paddress (gdbarch, next_pc));
@@ -8538,14 +8876,17 @@ remove_single_step_breakpoints (void)
/* Check whether a software single-step breakpoint is inserted at PC. */
static int
-single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
+single_step_breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc)
{
int i;
for (i = 0; i < 2; i++)
{
struct bp_target_info *bp_tgt = single_step_breakpoints[i];
- if (bp_tgt && bp_tgt->placed_address == pc)
+ if (bp_tgt
+ && breakpoint_address_match (bp_tgt->placed_address_space,
+ bp_tgt->placed_address,
+ aspace, pc))
return 1;
}
Index: src/gdb/exec.h
===================================================================
--- src.orig/gdb/exec.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/exec.h 2009-09-03 03:02:39.000000000 +0100
@@ -21,6 +21,7 @@
#define EXEC_H
#include "target.h"
+#include "symspace.h"
struct target_section;
struct target_ops;
@@ -28,6 +29,9 @@ struct bfd;
extern struct target_ops exec_ops;
+#define exec_bfd current_symbol_space->ebfd
+#define exec_bfd_mtime current_symbol_space->ebfd_mtime
+
/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
Returns 0 if OK, 1 on error. */
@@ -82,5 +86,6 @@ extern void add_target_sections (struct
extern void print_section_info (struct target_section_table *table,
bfd *abfd);
+extern void exec_close_1 (void);
#endif
^ permalink raw reply [flat|nested] 16+ messages in thread* [v4 2/2] multi-executable support
2009-09-03 2:49 [v4 0/2] multi-executable support Pedro Alves
2009-09-03 2:51 ` [v4 1/2] " Pedro Alves
@ 2009-09-03 2:53 ` Pedro Alves
2009-09-03 18:31 ` Eli Zaretskii
2009-09-03 2:56 ` [v4 0/2] multi-executable support (.gz) Pedro Alves
2 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2009-09-03 2:53 UTC (permalink / raw)
To: gdb-patches
Index: src/gdb/exec.c
===================================================================
--- src.orig/gdb/exec.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/exec.c 2009-09-03 03:02:39.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);
+ }
}
}
Index: src/gdb/gdbcore.h
===================================================================
--- src.orig/gdb/gdbcore.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gdbcore.h 2009-09-03 03:02:39.000000000 +0100
@@ -28,6 +28,7 @@ struct type;
struct regcache;
#include "bfd.h"
+#include "exec.h"
/* Return the name of the executable file as a string.
ERR nonzero means get error if there is none specified;
@@ -103,13 +104,9 @@ extern void (*deprecated_file_changed_ho
extern void specify_exec_file_hook (void (*hook) (char *filename));
-/* Binary File Diddlers for the exec and core files. */
+/* Binary File Diddler for the core file. */
extern bfd *core_bfd;
-extern bfd *exec_bfd;
-
-/* The mtime when we last opened exec_bfd. */
-extern long exec_bfd_mtime;
/* Whether to open exec and core files read-only or read-write. */
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/frame.h 2009-09-03 03:02:39.000000000 +0100
@@ -400,6 +400,15 @@ extern int frame_relative_level (struct
extern enum frame_type get_frame_type (struct frame_info *);
+/* Return the frame's symbol space. */
+extern struct symbol_space *get_frame_symbol_space (struct frame_info *);
+
+/* Unwind THIS frame's symbol space from the NEXT frame. */
+extern struct symbol_space *frame_unwind_symbol_space (struct frame_info *);
+
+/* Return the frame's address space. */
+extern struct address_space *get_frame_address_space (struct frame_info *);
+
/* For frames where we can not unwind further, describe why. */
enum unwind_stop_reason
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/frame.c 2009-09-03 03:02:39.000000000 +0100
@@ -70,6 +70,12 @@ struct frame_info
moment leave this as speculation. */
int level;
+ /* The frame's symbol space. */
+ struct symbol_space *sspace;
+
+ /* The frame's address space. */
+ struct address_space *aspace;
+
/* The frame's low-level unwinder and corresponding cache. The
low-level unwinder is responsible for unwinding register values
for the previous frame. The low-level unwind methods are
@@ -997,10 +1003,12 @@ put_frame_register_bytes (struct frame_i
/* Create a sentinel frame. */
static struct frame_info *
-create_sentinel_frame (struct regcache *regcache)
+create_sentinel_frame (struct symbol_space *sspace, struct regcache *regcache)
{
struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
frame->level = -1;
+ frame->sspace = sspace;
+ frame->aspace = get_regcache_aspace (regcache);
/* Explicitly initialize the sentinel frame's cache. Provide it
with the underlying regcache. In the future additional
information, such as the frame's thread will be added. */
@@ -1082,7 +1090,7 @@ get_current_frame (void)
if (current_frame == NULL)
{
struct frame_info *sentinel_frame =
- create_sentinel_frame (get_current_regcache ());
+ create_sentinel_frame (current_symbol_space, get_current_regcache ());
if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
RETURN_MASK_ERROR) != 0)
{
@@ -1213,7 +1221,7 @@ create_new_frame (CORE_ADDR addr, CORE_A
fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
- fi->next = create_sentinel_frame (get_current_regcache ());
+ fi->next = create_sentinel_frame (current_symbol_space, get_current_regcache ());
/* Set/update this frame's cached PC value, found in the next frame.
Do this before looking for this frame's unwinder. A sniffer is
@@ -1222,6 +1230,10 @@ create_new_frame (CORE_ADDR addr, CORE_A
fi->next->prev_pc.value = pc;
fi->next->prev_pc.p = 1;
+ /* We currently assume that frame chain's can't cross spaces. */
+ fi->sspace = fi->next->sspace;
+ fi->aspace = fi->next->aspace;
+
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
@@ -1494,6 +1506,11 @@ get_prev_frame_raw (struct frame_info *t
prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
prev_frame->level = this_frame->level + 1;
+ /* For now, assume we don't have frame chains crossing address
+ spaces. */
+ prev_frame->sspace = this_frame->sspace;
+ prev_frame->aspace = this_frame->aspace;
+
/* Don't yet compute ->unwind (and hence ->type). It is computed
on-demand in get_frame_type, frame_register_unwind, and
get_frame_id. */
@@ -1876,6 +1893,29 @@ get_frame_type (struct frame_info *frame
return frame->unwind->type;
}
+struct symbol_space *
+get_frame_symbol_space (struct frame_info *frame)
+{
+ return frame->sspace;
+}
+
+struct symbol_space *
+frame_unwind_symbol_space (struct frame_info *this_frame)
+{
+ gdb_assert (this_frame);
+
+ /* This is really a placeholder to keep the API consistent --- we
+ assume for now that we don't have frame chains crossing
+ spaces. */
+ return this_frame->sspace;
+}
+
+struct address_space *
+get_frame_address_space (struct frame_info *frame)
+{
+ return frame->aspace;
+}
+
/* Memory access methods. */
void
Index: src/gdb/stack.c
===================================================================
--- src.orig/gdb/stack.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/stack.c 2009-09-03 03:02:39.000000000 +0100
@@ -648,7 +648,8 @@ print_frame_info (struct frame_info *fra
}
if (print_what != LOCATION)
- set_default_breakpoint (1, get_frame_pc (frame), sal.symtab, sal.line);
+ set_default_breakpoint (1, sal.sspace,
+ get_frame_pc (frame), sal.symtab, sal.line);
annotate_frame_end ();
@@ -825,7 +826,8 @@ print_frame (struct frame_info *frame, i
#ifdef PC_SOLIB
char *lib = PC_SOLIB (get_frame_pc (frame));
#else
- char *lib = solib_name_from_address (get_frame_pc (frame));
+ char *lib = solib_name_from_address (get_frame_symbol_space (frame),
+ get_frame_pc (frame));
#endif
if (lib)
{
Index: src/gdb/gdbthread.h
===================================================================
--- src.orig/gdb/gdbthread.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gdbthread.h 2009-09-03 03:02:39.000000000 +0100
@@ -246,6 +246,10 @@ struct thread_info *first_thread_of_proc
/* Returns any thread of process PID. */
extern struct thread_info *any_thread_of_process (int pid);
+/* Returns any non-exited thread of process PID, giving preference for
+ already stopped threads. */
+extern struct thread_info *any_live_thread_of_process (int pid);
+
/* Change the ptid of thread OLD_PTID to NEW_PTID. */
void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/thread.c 2009-09-03 03:02:39.000000000 +0100
@@ -440,6 +440,24 @@ any_thread_of_process (int pid)
return NULL;
}
+struct thread_info *
+any_live_thread_of_process (int pid)
+{
+ struct thread_info *tp;
+ struct thread_info *tp_running = NULL;
+
+ for (tp = thread_list; tp; tp = tp->next)
+ if (ptid_get_pid (tp->ptid) == pid)
+ {
+ if (tp->state_ == THREAD_STOPPED)
+ return tp;
+ else if (tp->state_ == THREAD_RUNNING)
+ tp_running = tp;
+ }
+
+ return tp_running;
+}
+
/* Print a list of thread ids currently known, and the total number of
threads. To be used from within catch_errors. */
static int
@@ -849,6 +867,13 @@ switch_to_thread (ptid_t ptid)
return;
inferior_ptid = ptid;
+
+ /* Switch the symbol space as well, if we can infer it from the now
+ current thread. Otherwise, it's up to the caller to select the
+ space it wants. */
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ set_current_symbol_space (current_inferior ()->sspace);
+
reinit_frame_cache ();
registers_changed ();
@@ -913,7 +938,7 @@ restore_selected_frame (struct frame_id
select_frame (get_current_frame ());
/* Warn the user. */
- if (!ui_out_is_mi_like_p (uiout))
+ if (frame_level > 0 && !ui_out_is_mi_like_p (uiout))
{
warning (_("\
Couldn't restore frame #%d in current thread, at reparsed frame #0\n"),
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/inferior.h 2009-09-03 03:02:39.000000000 +0100
@@ -41,6 +41,8 @@ struct terminal_info;
/* For struct frame_id. */
#include "frame.h"
+#include "symspace.h"
+
/* Two structures are used to record inferior state.
inferior_thread_state contains state about the program itself like its
@@ -149,6 +151,11 @@ extern int step_stop_if_no_debug;
are kept running freely. */
extern int non_stop;
+/* If set (default), when following a fork, GDB will detach from one
+ the fork branches, child or parent. Exactly which branch is
+ detached depends on 'set follow-fork-mode' setting. */
+extern int detach_fork;
+
extern void generic_mourn_inferior (void);
extern void terminal_save_ours (void);
@@ -408,6 +415,12 @@ struct inferior
the ptid_t.pid member of threads of this inferior. */
int pid;
+ /* The address space bound to this inferior. */
+ struct address_space *aspace;
+
+ /* The symbol space bound to this inferior. */
+ struct symbol_space *sspace;
+
/* See the definition of stop_kind above. */
enum stop_kind stop_soon;
@@ -415,6 +428,25 @@ struct inferior
forked. */
int attach_flag;
+ /* If this inferior is a vfork child, then this is the pointer to
+ its vfork parent. Since a vfork parent is left stopped by the
+ kernel until the child execs or exits, a process can only have
+ one vfork parent. */
+ struct inferior *vfork_parent;
+
+ /* A vfork parent is left stopped by the kernel until the child
+ execs or exits, so a process can only have one vfork child. */
+ struct inferior *vfork_child;
+
+ /* True if this inferior should be detached when it's vfork sibling
+ exits or execs. */
+ int pending_detach;
+
+ /* True if this inferior is a vfork parent waiting for a vfork child
+ not under our control to be done with the shared memory region,
+ either by exiting or execing. */
+ int waiting_for_vfork_done;
+
/* What is left to do for an execution command after any thread of
this inferior stops. For continuations associated with a
specific thread, see `struct thread_info'. */
@@ -468,9 +500,16 @@ extern int in_inferior_list (int pid);
not the system's). */
extern int valid_gdb_inferior_id (int num);
-/* Search function to lookup a inferior by target 'pid'. */
+/* Search function to lookup an inferior by target 'pid'. */
extern struct inferior *find_inferior_pid (int pid);
+/* Search function to lookup an inferior by GDB 'num'. */
+extern struct inferior *find_inferior_id (int num);
+
+/* Find an inferior bound to SSPACE. */
+extern struct inferior *
+ find_inferior_for_symbol_space (struct symbol_space *sspace);
+
/* Inferior iterator function.
Calls a callback function once for each inferior, so long as the
@@ -502,4 +541,6 @@ extern int have_live_inferiors (void);
this if there is no current inferior. */
extern struct inferior *current_inferior (void);
+extern struct inferior *inferior_list;
+
#endif /* !defined (INFERIOR_H) */
Index: src/gdb/inferior.c
===================================================================
--- src.orig/gdb/inferior.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/inferior.c 2009-09-03 03:02:39.000000000 +0100
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "exec.h"
#include "inferior.h"
#include "target.h"
#include "command.h"
@@ -29,7 +30,7 @@
void _initialize_inferiors (void);
-static struct inferior *inferior_list = NULL;
+struct inferior *inferior_list = NULL;
static int highest_inferior_num;
/* Print notices on inferior events (attach, detach, etc.), set with
@@ -125,11 +126,12 @@ delete_thread_of_inferior (struct thread
/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
+
static void
delete_inferior_1 (int pid, int silent)
{
struct inferior *inf, *infprev;
- struct delete_thread_of_inferior_arg arg = { pid, silent };
+ struct delete_thread_of_inferior_arg arg;
infprev = NULL;
@@ -146,7 +148,7 @@ delete_inferior_1 (int pid, int silent)
iterate_over_threads (delete_thread_of_inferior, &arg);
/* Notify the observers before removing the inferior from the list,
- so that the observers have a change to look it up. */
+ so that the observers have a chance to look it up. */
observer_notify_inferior_exit (pid);
if (infprev)
@@ -193,7 +195,7 @@ discard_all_inferiors (void)
}
}
-static struct inferior *
+struct inferior *
find_inferior_id (int num)
{
struct inferior *inf;
@@ -217,6 +219,22 @@ find_inferior_pid (int pid)
return NULL;
}
+/* Find an inferior bound to SSPACE. */
+
+struct inferior *
+find_inferior_for_symbol_space (struct symbol_space *sspace)
+{
+ struct inferior *inf;
+
+ for (inf = inferior_list; inf != NULL; inf = inf->next)
+ {
+ if (inf->sspace == sspace)
+ return inf;
+ }
+
+ return NULL;
+}
+
struct inferior *
iterate_over_inferiors (int (*callback) (struct inferior *, void *),
void *data)
@@ -322,13 +340,15 @@ print_inferior (struct ui_out *uiout, in
return;
}
- old_chain = make_cleanup_ui_out_table_begin_end (uiout, 3, inf_count,
+ old_chain = make_cleanup_ui_out_table_begin_end (uiout, 5, inf_count,
"inferiors");
ui_out_table_header (uiout, 1, ui_left, "current", "");
ui_out_table_header (uiout, 4, ui_left, "number", "Num");
ui_out_table_header (uiout, 17, ui_left, "target-id", "Description");
- ui_out_table_body (uiout);
+ ui_out_table_header (uiout, 6, ui_left, "sspace-id", "SSpace");
+ ui_out_table_header (uiout, 17, ui_left, "exec", "Main Program");
+ ui_out_table_body (uiout);
for (inf = inferior_list; inf; inf = inf->next)
{
struct cleanup *chain2;
@@ -347,6 +367,28 @@ print_inferior (struct ui_out *uiout, in
ui_out_field_string (uiout, "target-id",
target_pid_to_str (pid_to_ptid (inf->pid)));
+ ui_out_field_int (uiout, "sspace-id", inf->sspace->num);
+
+ if (inf->sspace->ebfd)
+ ui_out_field_string (uiout, "exec",
+ bfd_get_filename (inf->sspace->ebfd));
+ else
+ ui_out_field_skip (uiout, "exec");
+
+ /* Print extra info that isn't really fit to always present in
+ tabular form. Currently we print the vfork parent/child
+ relationships, if any. */
+ if (inf->vfork_parent)
+ {
+ ui_out_text (uiout, _("\n\tis vfork child of inferior "));
+ ui_out_field_int (uiout, "vfork-parent", inf->vfork_parent->num);
+ }
+ if (inf->vfork_child)
+ {
+ ui_out_text (uiout, _("\n\tis vfork parent of inferior "));
+ ui_out_field_int (uiout, "vfork-child", inf->vfork_child->num);
+ }
+
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
Index: src/gdb/objfiles.h
===================================================================
--- src.orig/gdb/objfiles.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/objfiles.h 2009-09-03 03:02:39.000000000 +0100
@@ -23,6 +23,7 @@
#include "gdb_obstack.h" /* For obstack internals. */
#include "symfile.h" /* For struct psymbol_allocation_list */
+#include "symspace.h"
struct bcache;
struct htab;
@@ -200,6 +201,10 @@ struct objfile
unsigned short flags;
+ /* The symbol space associated with this objfile. */
+
+ struct symbol_space *sspace;
+
/* Each objfile points to a linked list of symtabs derived from this file,
one symtab structure for each compilation unit (source file). Each link
in the symtab list contains a backpointer to this objfile. */
@@ -414,11 +419,6 @@ struct objfile
#define OBJF_USERLOADED (1 << 3) /* User loaded */
-/* The object file that the main symbol table was loaded from (e.g. the
- argument to the "symbol-file" or "file" command). */
-
-extern struct objfile *symfile_objfile;
-
/* The object file that contains the runtime common minimal symbols
for SunOS4. Note that this objfile has no associated BFD. */
@@ -439,11 +439,6 @@ extern struct objfile *rt_common_objfile
extern struct objfile *current_objfile;
-/* All known objfiles are kept in a linked list. This points to the
- root of this list. */
-
-extern struct objfile *object_files;
-
/* Declarations for functions defined in objfiles.c */
extern struct objfile *allocate_objfile (bfd *, int);
@@ -513,14 +508,27 @@ extern struct bfd *gdb_bfd_ref (struct b
extern void gdb_bfd_unref (struct bfd *abfd);
\f
-/* Traverse all object files. ALL_OBJFILES_SAFE works even if you delete
- the objfile during the traversal. */
+/* Traverse all object files in the current symbol space.
+ ALL_OBJFILES_SAFE works even if you delete the objfile during the
+ traversal. */
+
+/* Traverse all object files in symbol space SS. */
-#define ALL_OBJFILES(obj) \
- for ((obj) = object_files; (obj) != NULL; (obj) = (obj)->next)
+#define ALL_SSPACE_OBJFILES(ss, obj) \
+ for ((obj) = ss->objfiles; (obj) != NULL; (obj) = (obj)->next) \
-#define ALL_OBJFILES_SAFE(obj,nxt) \
- for ((obj) = object_files; \
+#define ALL_SSPACE_OBJFILES_SAFE(ss, obj, nxt) \
+ for ((obj) = ss->objfiles; \
+ (obj) != NULL? ((nxt)=(obj)->next,1) :0; \
+ (obj) = (nxt))
+
+#define ALL_OBJFILES(obj) \
+ for ((obj) = current_symbol_space->objfiles; \
+ (obj) != NULL; \
+ (obj) = (obj)->next)
+
+#define ALL_OBJFILES_SAFE(obj,nxt) \
+ for ((obj) = current_symbol_space->objfiles; \
(obj) != NULL? ((nxt)=(obj)->next,1) :0; \
(obj) = (nxt))
@@ -539,27 +547,44 @@ extern void gdb_bfd_unref (struct bfd *a
#define ALL_OBJFILE_MSYMBOLS(objfile, m) \
for ((m) = (objfile) -> msymbols; SYMBOL_LINKAGE_NAME(m) != NULL; (m)++)
-/* Traverse all symtabs in all objfiles. */
+/* Traverse all symtabs in all objfiles in the current symbol
+ space. */
#define ALL_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s)
-/* Traverse all symtabs in all objfiles, skipping included files
- (which share a blockvector with their primary symtab). */
+#define ALL_SSPACE_SYMTABS(ss, objfile, s) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s)
+
+/* Traverse all symtabs in all objfiles in the current symbol space,
+ skipping included files (which share a blockvector with their
+ primary symtab). */
#define ALL_PRIMARY_SYMTABS(objfile, s) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_SYMTABS (objfile, s) \
if ((s)->primary)
-/* Traverse all psymtabs in all objfiles. */
+#define ALL_SSPACE_PRIMARY_SYMTABS(sspace, objfile, s) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_SYMTABS (objfile, s) \
+ if ((s)->primary)
+
+/* Traverse all psymtabs in all objfiles in the current symbol
+ space. */
#define ALL_PSYMTABS(objfile, p) \
ALL_OBJFILES (objfile) \
ALL_OBJFILE_PSYMTABS (objfile, p)
-/* Traverse all minimal symbols in all objfiles. */
+#define ALL_SSPACE_PSYMTABS(ss, objfile, p) \
+ ALL_SSPACE_OBJFILES (ss, objfile) \
+ ALL_OBJFILE_PSYMTABS (objfile, p)
+
+/* Traverse all minimal symbols in all objfiles in the current symbol
+ space. */
#define ALL_MSYMBOLS(objfile, m) \
ALL_OBJFILES (objfile) \
Index: src/gdb/objfiles.c
===================================================================
--- src.orig/gdb/objfiles.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/objfiles.c 2009-09-03 03:02:39.000000000 +0100
@@ -60,16 +60,53 @@ static void objfile_free_data (struct ob
/* Externally visible variables that are owned by this module.
See declarations in objfile.h for more info. */
-struct objfile *object_files; /* Linked list of all objfiles */
struct objfile *current_objfile; /* For symbol file being read in */
-struct objfile *symfile_objfile; /* Main symbol table loaded from */
struct objfile *rt_common_objfile; /* For runtime common symbols */
+struct objfile_sspace_info
+{
+ int objfiles_changed_p;
+ struct obj_section **sections;
+ int num_sections;
+};
+
+/* Per-symbol-space data key. */
+static const struct symbol_space_data *objfiles_sspace_data;
+
+static void
+objfiles_sspace_data_cleanup (struct symbol_space *sspace, void *arg)
+{
+ struct objfile_sspace_info *info;
+
+ info = symbol_space_data (sspace, objfiles_sspace_data);
+ if (info != NULL)
+ {
+ xfree (info->sections);
+ xfree (info);
+ }
+}
+
+/* Get the current svr4 data. If none is found yet, add it now. This
+ function always returns a valid object. */
+
+static struct objfile_sspace_info *
+get_objfile_sspace_data (struct symbol_space *sspace)
+{
+ struct objfile_sspace_info *info;
+
+ info = symbol_space_data (sspace, objfiles_sspace_data);
+ if (info == NULL)
+ {
+ info = XZALLOC (struct objfile_sspace_info);
+ set_symbol_space_data (sspace, objfiles_sspace_data, info);
+ }
+
+ return info;
+}
+
/* Records whether any objfiles appeared or disappeared since we last updated
address to obj section map. */
-static int objfiles_changed_p;
-
/* Locate all mappable sections of a BFD file.
objfile_p_char is a char * to get it through
bfd_map_over_sections; we cast it back to its proper type. */
@@ -207,6 +244,8 @@ allocate_objfile (bfd *abfd, int flags)
objfile->name = xstrdup ("<<anonymous objfile>>");
}
+ objfile->sspace = current_symbol_space;
+
/* Initialize the section indexes for this objfile, so that we can
later detect if they are used w/o being properly assigned to. */
@@ -235,9 +274,10 @@ allocate_objfile (bfd *abfd, int flags)
/* Save passed in flag bits. */
objfile->flags |= flags;
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
+ /* Rebuild section map next time we need it. */
+ get_objfile_sspace_data (objfile->sspace)->objfiles_changed_p = 1;
- return (objfile);
+ return objfile;
}
/* Retrieve the gdbarch associated with OBJFILE. */
@@ -511,9 +551,11 @@ free_objfile (struct objfile *objfile)
if (objfile->demangled_names_hash)
htab_delete (objfile->demangled_names_hash);
obstack_free (&objfile->objfile_obstack, 0);
+
+ /* Rebuild section map next time we need it. */
+ get_objfile_sspace_data (objfile->sspace)->objfiles_changed_p = 1;
+
xfree (objfile);
- objfile = NULL;
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
}
static void
@@ -685,7 +727,7 @@ objfile_relocate (struct objfile *objfil
}
/* Rebuild section map next time we need it. */
- objfiles_changed_p = 1;
+ get_objfile_sspace_data (objfile->sspace)->objfiles_changed_p = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
@@ -838,13 +880,15 @@ preferred_obj_section (struct obj_sectio
/* Update PMAP, PMAP_SIZE with non-TLS sections from all objfiles. */
static void
-update_section_map (struct obj_section ***pmap, int *pmap_size)
+update_section_map (struct symbol_space *sspace,
+ struct obj_section ***pmap, int *pmap_size)
{
int map_size, i, j;
struct obj_section *s, **map;
struct objfile *objfile;
- gdb_assert (objfiles_changed_p != 0);
+ /* Rebuild section map next time we need it. */
+ gdb_assert (get_objfile_sspace_data (sspace)->objfiles_changed_p != 0);
map = *pmap;
xfree (map);
@@ -854,16 +898,18 @@ update_section_map (struct obj_section *
& SEC_THREAD_LOCAL) == 0)
map_size = 0;
- ALL_OBJSECTIONS (objfile, s)
- if (insert_p (objfile, s))
- map_size += 1;
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ if (insert_p (objfile, s))
+ map_size += 1;
map = xmalloc (map_size * sizeof (*map));
i = 0;
- ALL_OBJSECTIONS (objfile, s)
- if (insert_p (objfile, s))
- map[i++] = s;
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ ALL_OBJFILE_OSECTIONS (objfile, s)
+ if (insert_p (objfile, s))
+ map[i++] = s;
#undef insert_p
@@ -923,9 +969,7 @@ bsearch_cmp (const void *key, const void
struct obj_section *
find_pc_section (CORE_ADDR pc)
{
- static struct obj_section **sections;
- static int num_sections;
-
+ struct objfile_sspace_info *sspace_info;
struct obj_section *s, **sp;
/* Check for mapped overlay section first. */
@@ -933,17 +977,23 @@ find_pc_section (CORE_ADDR pc)
if (s)
return s;
- if (objfiles_changed_p != 0)
+ sspace_info = get_objfile_sspace_data (current_symbol_space);
+ if (sspace_info->objfiles_changed_p != 0)
{
- update_section_map (§ions, &num_sections);
-
- /* Don't need updates to section map until objfiles are added
- or removed. */
- objfiles_changed_p = 0;
- }
-
- sp = (struct obj_section **) bsearch (&pc, sections, num_sections,
- sizeof (*sections), bsearch_cmp);
+ update_section_map (current_symbol_space,
+ &sspace_info->sections,
+ &sspace_info->num_sections);
+
+ /* Don't need updates to section map until objfiles are added,
+ removed or relocated. */
+ sspace_info->objfiles_changed_p = 0;
+ }
+
+ sp = (struct obj_section **) bsearch (&pc,
+ sspace_info->sections,
+ sspace_info->num_sections,
+ sizeof (*sspace_info->sections),
+ bsearch_cmp);
if (sp != NULL)
return *sp;
return NULL;
@@ -1071,7 +1121,8 @@ objfile_data (struct objfile *objfile, c
void
objfiles_changed (void)
{
- objfiles_changed_p = 1; /* Rebuild section map next time we need it. */
+ /* Rebuild section map next time we need it. */
+ get_objfile_sspace_data (current_symbol_space)->objfiles_changed_p = 1;
}
/* Add reference to ABFD. Returns ABFD. */
@@ -1122,3 +1173,13 @@ gdb_bfd_unref (struct bfd *abfd)
name, bfd_errmsg (bfd_get_error ()));
xfree (name);
}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_objfiles;
+
+void
+_initialize_objfiles (void)
+{
+ objfiles_sspace_data
+ = register_symbol_space_data_with_cleanup (objfiles_sspace_data_cleanup);
+}
Index: src/gdb/linespec.c
===================================================================
--- src.orig/gdb/linespec.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/linespec.c 2009-09-03 03:02:39.000000000 +0100
@@ -1573,6 +1573,8 @@ decode_all_digits (char **argptr, struct
init_sal (&val);
+ val.sspace = current_symbol_space;
+
/* This is where we need to make sure that we have good defaults.
We must guarantee that this section of code is never executed
when we are called with just a function name, since
@@ -1624,6 +1626,7 @@ decode_all_digits (char **argptr, struct
if (val.symtab == 0)
val.symtab = file_symtab;
+ val.sspace = SYMTAB_SSPACE (val.symtab);
val.pc = 0;
values.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
@@ -1695,6 +1698,7 @@ decode_dollar (char *copy, int funfirstl
val.symtab = file_symtab ? file_symtab : default_symtab;
val.line = valx;
val.pc = 0;
+ val.sspace = current_symbol_space;
values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
values.sals[0] = val;
Index: src/gdb/source.c
===================================================================
--- src.orig/gdb/source.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/source.c 2009-09-03 03:02:39.000000000 +0100
@@ -92,6 +92,8 @@ static struct symtab *current_source_sym
static int current_source_line;
+static struct symbol_space *current_source_sspace;
+
/* Default number of lines to print with commands like "list".
This is based on guessing how many long (i.e. more than chars_per_line
characters) lines there will be. To be completely correct, "list"
@@ -152,6 +154,7 @@ get_current_source_symtab_and_line (void
{
struct symtab_and_line cursal = { 0 };
+ cursal.sspace = current_source_sspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
cursal.pc = 0;
@@ -190,15 +193,17 @@ struct symtab_and_line
set_current_source_symtab_and_line (const struct symtab_and_line *sal)
{
struct symtab_and_line cursal = { 0 };
-
+
+ cursal.sspace = current_source_sspace;
cursal.symtab = current_source_symtab;
cursal.line = current_source_line;
+ cursal.pc = 0;
+ cursal.end = 0;
+ current_source_sspace = sal->sspace;
current_source_symtab = sal->symtab;
current_source_line = sal->line;
- cursal.pc = 0;
- cursal.end = 0;
-
+
return cursal;
}
@@ -232,6 +237,7 @@ select_source_symtab (struct symtab *s)
{
current_source_symtab = s;
current_source_line = 1;
+ current_source_sspace = SYMTAB_SSPACE (s);
return;
}
@@ -245,6 +251,7 @@ select_source_symtab (struct symtab *s)
sals = decode_line_spec (main_name (), 1);
sal = sals.sals[0];
xfree (sals.sals);
+ current_source_sspace = sal.sspace;
current_source_symtab = sal.symtab;
current_source_line = max (sal.line - (lines_to_list - 1), 1);
if (current_source_symtab)
@@ -256,7 +263,7 @@ select_source_symtab (struct symtab *s)
current_source_line = 1;
- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES (ofp)
{
for (s = ofp->symtabs; s; s = s->next)
{
@@ -264,15 +271,19 @@ select_source_symtab (struct symtab *s)
int len = strlen (name);
if (!(len > 2 && (strcmp (&name[len - 2], ".h") == 0
|| strcmp (name, "<<C++-namespaces>>") == 0)))
- current_source_symtab = s;
+ {
+ current_source_sspace = current_symbol_space;
+ current_source_symtab = s;
+ }
}
}
+
if (current_source_symtab)
return;
/* How about the partial symbol tables? */
- for (ofp = object_files; ofp != NULL; ofp = ofp->next)
+ ALL_OBJFILES (ofp)
{
for (ps = ofp->psymtabs; ps != NULL; ps = ps->next)
{
@@ -293,6 +304,7 @@ select_source_symtab (struct symtab *s)
}
else
{
+ current_source_sspace = current_symbol_space;
current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
}
}
@@ -317,11 +329,13 @@ show_directories (char *ignore, int from
void
forget_cached_source_info (void)
{
+ struct symbol_space *sspace;
struct symtab *s;
struct objfile *objfile;
struct partial_symtab *pst;
- for (objfile = object_files; objfile != NULL; objfile = objfile->next)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
for (s = objfile->symtabs; s != NULL; s = s->next)
{
Index: src/gdb/symfile.c
===================================================================
--- src.orig/gdb/symfile.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/symfile.c 2009-09-03 03:02:39.000000000 +0100
@@ -2809,7 +2809,7 @@ clear_symtab_users (void)
clear_displays ();
breakpoint_re_set ();
- set_default_breakpoint (0, 0, 0, 0);
+ set_default_breakpoint (0, NULL, 0, 0, 0);
clear_pc_function_cache ();
observer_notify_new_objfile (NULL);
Index: src/gdb/symmisc.c
===================================================================
--- src.orig/gdb/symmisc.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/symmisc.c 2009-09-03 03:02:39.000000000 +0100
@@ -130,10 +130,12 @@ free_symtab (struct symtab *s)
void
print_symbol_bcache_statistics (void)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
immediate_quit++;
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
printf_filtered (_("Byte cache statistics for '%s':\n"), objfile->name);
print_bcache_statistics (objfile->psymbol_cache, "partial symbol cache");
@@ -145,13 +147,15 @@ print_symbol_bcache_statistics (void)
void
print_objfile_statistics (void)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
struct symtab *s;
struct partial_symtab *ps;
int i, linetables, blockvectors;
immediate_quit++;
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
printf_filtered (_("Statistics for '%s':\n"), objfile->name);
if (OBJSTAT (objfile, n_stabs) > 0)
@@ -886,6 +890,7 @@ maintenance_print_msymbols (char *args,
struct cleanup *cleanups;
char *filename = DEV_TTY;
char *symname = NULL;
+ struct symbol_space *sspace;
struct objfile *objfile;
struct stat sym_st, obj_st;
@@ -921,10 +926,11 @@ maintenance_print_msymbols (char *args,
make_cleanup_ui_file_delete (outfile);
immediate_quit++;
- ALL_OBJFILES (objfile)
- if (symname == NULL
- || (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
- dump_msymbols (objfile, outfile);
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ if (symname == NULL
+ || (!stat (objfile->name, &obj_st) && sym_st.st_ino == obj_st.st_ino))
+ dump_msymbols (objfile, outfile);
immediate_quit--;
fprintf_filtered (outfile, "\n\n");
do_cleanups (cleanups);
@@ -933,13 +939,15 @@ maintenance_print_msymbols (char *args,
void
maintenance_print_objfiles (char *ignore, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
dont_repeat ();
immediate_quit++;
- ALL_OBJFILES (objfile)
- dump_objfile (objfile);
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
+ dump_objfile (objfile);
immediate_quit--;
}
@@ -948,12 +956,14 @@ maintenance_print_objfiles (char *ignore
void
maintenance_info_symtabs (char *regexp, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
if (regexp)
re_comp (regexp);
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
struct symtab *symtab;
@@ -1005,12 +1015,14 @@ maintenance_info_symtabs (char *regexp,
void
maintenance_info_psymtabs (char *regexp, int from_tty)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
if (regexp)
re_comp (regexp);
- ALL_OBJFILES (objfile)
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_OBJFILES (sspace, objfile)
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
struct partial_symtab *psymtab;
Index: src/gdb/symtab.h
===================================================================
--- src.orig/gdb/symtab.h 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/symtab.h 2009-09-03 03:02:39.000000000 +0100
@@ -32,6 +32,7 @@ struct block;
struct blockvector;
struct axs_value;
struct agent_expr;
+struct symbol_space;
/* Some of the structures in this file are space critical.
The space-critical structures are:
@@ -823,6 +824,7 @@ struct symtab
#define BLOCKVECTOR(symtab) (symtab)->blockvector
#define LINETABLE(symtab) (symtab)->linetable
+#define SYMTAB_SSPACE(symtab) (symtab)->objfile->sspace
\f
/* Each source file that has not been fully read in is represented by
@@ -1170,6 +1172,9 @@ extern void msymbols_sort (struct objfil
struct symtab_and_line
{
+ /* The symbol space of this sal. */
+ struct symbol_space *sspace;
+
struct symtab *symtab;
struct obj_section *section;
/* Line number. Line numbers start at 1 and proceed through symtab->nlines.
Index: src/gdb/symtab.c
===================================================================
--- src.orig/gdb/symtab.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/symtab.c 2009-09-03 03:02:39.000000000 +0100
@@ -690,6 +690,7 @@ symbol_search_name (const struct general
void
init_sal (struct symtab_and_line *sal)
{
+ sal->sspace = NULL;
sal->symtab = 0;
sal->section = 0;
sal->line = 0;
@@ -1994,9 +1995,12 @@ find_pc_sect_symtab (CORE_ADDR pc, struc
struct symtab *best_s = NULL;
struct partial_symtab *ps;
struct objfile *objfile;
+ struct symbol_space *sspace;
CORE_ADDR distance = 0;
struct minimal_symbol *msymbol;
+ sspace = current_symbol_space;
+
/* If we know that this is not a text address, return failure. This is
necessary because we loop based on the block's high and low code
addresses, which do not include the data ranges, and because
@@ -2152,6 +2156,8 @@ find_pc_sect_line (CORE_ADDR pc, struct
init_sal (&val); /* initialize to zeroes */
+ val.sspace = current_symbol_space;
+
/* It's tempting to assume that, if we can't find debugging info for
any function enclosing PC, that we shouldn't search for line
number info, either. However, GAS can emit line number info for
@@ -2656,6 +2662,11 @@ find_function_start_sal (struct symbol *
struct symtab_and_line sal;
struct block *b, *function_block;
+ struct cleanup *old_chain;
+
+ old_chain = save_current_space_and_thread ();
+ switch_to_symbol_space_and_thread (objfile->sspace);
+
pc = BLOCK_START (block);
fixup_symbol_section (sym, objfile);
if (funfirstline)
@@ -2707,6 +2718,7 @@ find_function_start_sal (struct symbol *
}
sal.pc = pc;
+ sal.sspace = objfile->sspace;
/* Check if we are now inside an inlined function. If we can,
use the call site of the function instead. */
@@ -2727,6 +2739,7 @@ find_function_start_sal (struct symbol *
sal.symtab = SYMBOL_SYMTAB (BLOCK_FUNCTION (function_block));
}
+ do_cleanups (old_chain);
return sal;
}
@@ -4560,6 +4573,7 @@ symtab_observer_executable_changed (void
initializing it from SYMTAB, LINENO and PC. */
static void
append_expanded_sal (struct symtabs_and_lines *sal,
+ struct symbol_space *sspace,
struct symtab *symtab,
int lineno, CORE_ADDR pc)
{
@@ -4567,6 +4581,7 @@ append_expanded_sal (struct symtabs_and_
sizeof (sal->sals[0])
* (sal->nelts + 1));
init_sal (sal->sals + sal->nelts);
+ sal->sals[sal->nelts].sspace = sspace;
sal->sals[sal->nelts].symtab = symtab;
sal->sals[sal->nelts].section = NULL;
sal->sals[sal->nelts].end = 0;
@@ -4586,14 +4601,16 @@ append_exact_match_to_sals (char *filena
struct linetable_entry **best_item,
struct symtab **best_symtab)
{
+ struct symbol_space *sspace;
struct objfile *objfile;
struct symtab *symtab;
int exact = 0;
int j;
*best_item = 0;
*best_symtab = 0;
-
- ALL_SYMTABS (objfile, symtab)
+
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_SYMTABS (sspace, objfile, symtab)
{
if (strcmp (filename, symtab->filename) == 0)
{
@@ -4611,7 +4628,8 @@ append_exact_match_to_sals (char *filena
if (item->line == lineno)
{
exact = 1;
- append_expanded_sal (ret, symtab, lineno, item->pc);
+ append_expanded_sal (ret, objfile->sspace,
+ symtab, lineno, item->pc);
}
else if (!exact && item->line > lineno
&& (*best_item == NULL
@@ -4626,11 +4644,10 @@ append_exact_match_to_sals (char *filena
return exact;
}
-/* Compute a set of all sals in
- the entire program that correspond to same file
- and line as SAL and return those. If there
- are several sals that belong to the same block,
- only one sal for the block is included in results. */
+/* Compute a set of all sals in all symbol spaces that correspond to
+ same file and line as SAL and return those. If there are several
+ sals that belong to the same block, only one sal for the block is
+ included in results. */
struct symtabs_and_lines
expand_line_sal (struct symtab_and_line sal)
@@ -4644,10 +4661,12 @@ expand_line_sal (struct symtab_and_line
int deleted = 0;
struct block **blocks = NULL;
int *filter;
+ struct cleanup *old_chain;
ret.nelts = 0;
ret.sals = NULL;
+ /* Only expand sals that represent file.c:line. */
if (sal.symtab == NULL || sal.line == 0 || sal.pc != 0)
{
ret.sals = xmalloc (sizeof (struct symtab_and_line));
@@ -4657,11 +4676,14 @@ expand_line_sal (struct symtab_and_line
}
else
{
+ struct symbol_space *sspace;
struct linetable_entry *best_item = 0;
struct symtab *best_symtab = 0;
int exact = 0;
+ char *match_filename;
lineno = sal.line;
+ match_filename = sal.symtab->filename;
/* We need to find all symtabs for a file which name
is described by sal. We cannot just directly
@@ -4674,17 +4696,23 @@ expand_line_sal (struct symtab_and_line
the right name. Then, we iterate over symtabs, knowing
that all symtabs we're interested in are loaded. */
- ALL_PSYMTABS (objfile, psymtab)
+ old_chain = save_current_symbol_space ();
+ ALL_SSPACES (sspace)
+ ALL_SSPACE_PSYMTABS (sspace, objfile, psymtab)
{
- if (strcmp (sal.symtab->filename,
- psymtab->filename) == 0)
- PSYMTAB_TO_SYMTAB (psymtab);
+ if (strcmp (match_filename, psymtab->filename) == 0)
+ {
+ set_current_symbol_space (sspace);
+
+ PSYMTAB_TO_SYMTAB (psymtab);
+ }
}
+ do_cleanups (old_chain);
/* Now search the symtab for exact matches and append them. If
none is found, append the best_item and all its exact
matches. */
- exact = append_exact_match_to_sals (sal.symtab->filename, lineno,
+ exact = append_exact_match_to_sals (match_filename, lineno,
&ret, &best_item, &best_symtab);
if (!exact && best_item)
append_exact_match_to_sals (best_symtab->filename, best_item->line,
@@ -4700,13 +4728,21 @@ expand_line_sal (struct symtab_and_line
blocks -- for each PC found above we see if there are other PCs
that are in the same block. If yes, the other PCs are filtered out. */
+ old_chain = save_current_symbol_space ();
filter = alloca (ret.nelts * sizeof (int));
blocks = alloca (ret.nelts * sizeof (struct block *));
for (i = 0; i < ret.nelts; ++i)
{
+ struct blockvector *bl;
+ struct block *b;
+
+ set_current_symbol_space (ret.sals[i].sspace);
+
filter[i] = 1;
- blocks[i] = block_for_pc (ret.sals[i].pc);
+ blocks[i] = block_for_pc_sect (ret.sals[i].pc, ret.sals[i].section);
+
}
+ do_cleanups (old_chain);
for (i = 0; i < ret.nelts; ++i)
if (blocks[i] != NULL)
Index: src/gdb/target.h
===================================================================
--- src.orig/gdb/target.h 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/target.h 2009-09-03 03:02:39.000000000 +0100
@@ -110,6 +110,15 @@ enum target_waitkind
TARGET_WAITKIND_EXECD,
+ /* The program had previously vforked, and now the child is done
+ with the shared memory region, because it exec'ed or exited.
+ Note that the event if reported to the vfork parent. This is
+ only used if GDB did not stay attached to the vfork child,
+ otherwise, a TARGET_WAITKIND_EXECD or
+ TARGET_WAITKIND_EXIT|SIGNALLED event associated with the child
+ has the same effect. */
+ TARGET_WAITKIND_VFORK_DONE,
+
/* The program has entered or returned from a system call. On
HP-UX, this is used in the hardware watchpoint implementation.
The syscall's unique integer ID number is in value.syscall_id */
@@ -668,6 +677,10 @@ extern void target_store_registers (stru
#define target_prepare_to_store(regcache) \
(*current_target.to_prepare_to_store) (regcache)
+/* Determine current address space of thread PTID. */
+
+struct address_space *target_thread_address_space (ptid_t);
+
/* Returns true if this target can debug multiple processes
simultaneously. */
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/target.c 2009-09-03 03:02:39.000000000 +0100
@@ -2041,7 +2041,7 @@ target_detach (char *args, int from_tty)
else
/* If we're in breakpoints-always-inserted mode, have to remove
them before detaching. */
- remove_breakpoints ();
+ remove_breakpoints_pid (PIDGET (inferior_ptid));
for (t = current_target.beneath; t != NULL; t = t->beneath)
{
@@ -2542,6 +2542,27 @@ target_get_osdata (const char *type)
return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type);
}
+/* Determine the current address space of thread PTID. */
+
+struct address_space *
+target_thread_address_space (ptid_t ptid)
+{
+ struct inferior *inf;
+
+ /* For now, assume frame chains and inferiors only see one address
+ space. */
+
+ /* Fall-back to the "main" address space of the inferior. */
+ inf = find_inferior_pid (ptid_get_pid (ptid));
+
+ if (inf == NULL || inf->aspace == NULL)
+ internal_error (__FILE__, __LINE__, "\
+Can't determine the current address space of thread %s\n",
+ target_pid_to_str (ptid));
+
+ return inf->aspace;
+}
+
static int
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
{
Index: src/gdb/defs.h
===================================================================
--- src.orig/gdb/defs.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/defs.h 2009-09-03 03:02:39.000000000 +0100
@@ -1220,4 +1220,8 @@ extern ULONGEST align_down (ULONGEST v,
void *hashtab_obstack_allocate (void *data, size_t size, size_t count);
void dummy_obstack_deallocate (void *object, void *data);
+/* From symspace.c */
+
+extern void initialize_symspace (void);
+
#endif /* #ifndef DEFS_H */
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/top.c 2009-09-03 03:02:39.000000000 +0100
@@ -1683,6 +1683,12 @@ gdb_init (char *argv0)
initialize_targets (); /* Setup target_terminal macros for utils.c */
initialize_utils (); /* Make errors and warnings possible */
initialize_all_files ();
+ /* This creates the current_symbol_space. Do this after all the
+ _initialize_foo routines have had a chance to install their
+ per-sspace data keys. Also do this before
+ initialize_current_architecture is called, because it accesses
+ exec_bfd of the current symbol space. */
+ initialize_symspace ();
initialize_current_architecture ();
init_cli_cmds();
init_main (); /* But that omits this file! Do it now */
Index: src/gdb/solist.h
===================================================================
--- src.orig/gdb/solist.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/solist.h 2009-09-03 03:02:39.000000000 +0100
@@ -52,6 +52,9 @@ struct so_list
/* shared object file name, expanded to something GDB can open */
char so_name[SO_NAME_MAX_PATH_SIZE];
+ /* Symbol space this shared library belongs to. */
+ struct symbol_space *sspace;
+
/* The following fields of the structure are built from
information gathered from the shared object file itself, and
are set when we actually add it to our symbol tables.
Index: src/gdb/solib.h
===================================================================
--- src.orig/gdb/solib.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/solib.h 2009-09-03 03:02:39.000000000 +0100
@@ -25,6 +25,7 @@
struct so_list;
struct target_ops;
struct target_so_ops;
+struct symbol_space;
/* Called when we free all symtabs, to free the shared library information
as well. */
@@ -45,7 +46,7 @@ extern void solib_create_inferior_hook (
/* If ADDR lies in a shared library, return its name. */
-extern char *solib_name_from_address (CORE_ADDR);
+extern char *solib_name_from_address (struct symbol_space *, CORE_ADDR);
/* Return 1 if ADDR lies within SOLIB. */
Index: src/gdb/solib.c
===================================================================
--- src.orig/gdb/solib.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/solib.c 2009-09-03 03:02:39.000000000 +0100
@@ -86,9 +86,8 @@ set_solib_ops (struct gdbarch *gdbarch,
configuration needs to call set_solib_ops. */
struct target_so_ops *current_target_so_ops;
-/* local data declarations */
-
-static struct so_list *so_list_head; /* List of known shared objects */
+/* List of known shared objects */
+#define so_list_head current_symbol_space->so_list
/* Local function prototypes */
@@ -651,6 +650,7 @@ update_solib_list (int from_tty, struct
for (i = inferior; i; i = i->next)
{
i->from_tty = from_tty;
+ i->sspace = current_symbol_space;
/* Fill in the rest of the `struct so_list' node. */
catch_errors (solib_map_sections, i,
@@ -937,11 +937,11 @@ solib_contains_address_p (const struct s
*/
char *
-solib_name_from_address (CORE_ADDR address)
+solib_name_from_address (struct symbol_space *sspace, CORE_ADDR address)
{
- struct so_list *so = 0; /* link map state variable */
+ struct so_list *so = NULL;
- for (so = so_list_head; so; so = so->next)
+ for (so = sspace->so_list; so; so = so->next)
if (solib_contains_address_p (so, address))
return (so->so_name);
Index: src/gdb/solib-svr4.c
===================================================================
--- src.orig/gdb/solib-svr4.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/solib-svr4.c 2009-09-03 03:02:39.000000000 +0100
@@ -273,12 +273,10 @@ IGNORE_FIRST_LINK_MAP_ENTRY (struct so_l
ptr_type) == 0;
}
-/* Per-inferior SVR4 specific data. */
+/* Per sspace SVR4 specific data. */
struct svr4_info
{
- int pid;
-
CORE_ADDR debug_base; /* Base of dynamic linker structures */
/* Validity flag for debug_loader_offset. */
@@ -292,69 +290,40 @@ struct svr4_info
/* Load map address for the main executable. */
CORE_ADDR main_lm_addr;
-};
-
-/* List of known processes using solib-svr4 shared libraries, storing
- the required bookkeeping for each. */
-
-typedef struct svr4_info *svr4_info_p;
-DEF_VEC_P(svr4_info_p);
-VEC(svr4_info_p) *svr4_info = NULL;
-
-/* Get svr4 data for inferior PID (target id). If none is found yet,
- add it now. This function always returns a valid object. */
-
-struct svr4_info *
-get_svr4_info (int pid)
-{
- int ix;
- struct svr4_info *it;
-
- gdb_assert (pid != 0);
- for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
- {
- if (it->pid == pid)
- return it;
- }
-
- it = XZALLOC (struct svr4_info);
- it->pid = pid;
-
- VEC_safe_push (svr4_info_p, svr4_info, it);
-
- return it;
-}
+ CORE_ADDR interp_text_sect_low;
+ CORE_ADDR interp_text_sect_high;
+ CORE_ADDR interp_plt_sect_low;
+ CORE_ADDR interp_plt_sect_high;
+};
-/* Get rid of any svr4 related bookkeeping for inferior PID (target
- id). */
+/* Per-symbol-space data key. */
+static const struct symbol_space_data *solib_svr4_sspace_data;
static void
-remove_svr4_info (int pid)
+svr4_sspace_data_cleanup (struct symbol_space *sspace, void *arg)
{
- int ix;
- struct svr4_info *it;
+ struct svr4_info *info;
- for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix)
- {
- if (it->pid == pid)
- {
- VEC_unordered_remove (svr4_info_p, svr4_info, ix);
- return;
- }
- }
+ info = symbol_space_data (sspace, solib_svr4_sspace_data);
+ xfree (info);
}
-/* This is an "inferior_exit" observer. Inferior PID (target id) is
- being removed from the inferior list, because it exited, was
- killed, detached, or we just dropped the connection to the debug
- interface --- discard any solib-svr4 related bookkeeping for this
- inferior. */
+/* Get the current svr4 data. If none is found yet, add it now. This
+ function always returns a valid object. */
-static void
-solib_svr4_inferior_exit (int pid)
+static struct svr4_info *
+get_svr4_info (void)
{
- remove_svr4_info (pid);
+ struct svr4_info *info;
+
+ info = symbol_space_data (current_symbol_space, solib_svr4_sspace_data);
+ if (info != NULL)
+ return info;
+
+ info = XZALLOC (struct svr4_info);
+ set_symbol_space_data (current_symbol_space, solib_svr4_sspace_data, info);
+ return info;
}
/* Local function prototypes */
@@ -931,7 +900,7 @@ open_symbol_file_object (void *from_ttyp
int l_name_size = TYPE_LENGTH (ptr_type);
gdb_byte *l_name_buf = xmalloc (l_name_size);
struct cleanup *cleanups = make_cleanup (xfree, l_name_buf);
- struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
+ struct svr4_info *info = get_svr4_info ();
if (symfile_objfile)
if (!query (_("Attempt to reload symbols from process? ")))
@@ -982,8 +951,7 @@ open_symbol_file_object (void *from_ttyp
static struct so_list *
svr4_default_sos (void)
{
- struct inferior *inf = current_inferior ();
- struct svr4_info *info = get_svr4_info (inf->pid);
+ struct svr4_info *info = get_svr4_info ();
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
@@ -1038,14 +1006,9 @@ svr4_current_sos (void)
struct so_list *head = 0;
struct so_list **link_ptr = &head;
CORE_ADDR ldsomap = 0;
- struct inferior *inf;
struct svr4_info *info;
- if (ptid_equal (inferior_ptid, null_ptid))
- return NULL;
-
- inf = current_inferior ();
- info = get_svr4_info (inf->pid);
+ info = get_svr4_info ();
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
@@ -1142,7 +1105,7 @@ CORE_ADDR
svr4_fetch_objfile_link_map (struct objfile *objfile)
{
struct so_list *so;
- struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid));
+ struct svr4_info *info = get_svr4_info ();
/* Cause svr4_current_sos() to be run if it hasn't been already. */
if (info->main_lm_addr == 0)
@@ -1182,16 +1145,16 @@ match_main (char *soname)
/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
-static CORE_ADDR interp_text_sect_low;
-static CORE_ADDR interp_text_sect_high;
-static CORE_ADDR interp_plt_sect_low;
-static CORE_ADDR interp_plt_sect_high;
int
svr4_in_dynsym_resolve_code (CORE_ADDR pc)
{
- return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
- || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
+ struct svr4_info *info = get_svr4_info ();
+
+ return ((pc >= info->interp_text_sect_low
+ && pc < info->interp_text_sect_high)
+ || (pc >= info->interp_plt_sect_low
+ && pc < info->interp_plt_sect_high)
|| in_plt_section (pc, NULL));
}
@@ -1265,14 +1228,13 @@ enable_break (struct svr4_info *info)
asection *interp_sect;
gdb_byte *interp_name;
CORE_ADDR sym_addr;
- struct inferior *inf = current_inferior ();
/* First, remove all the solib event breakpoints. Their addresses
may have changed since the last time we ran the program. */
remove_solib_event_breakpoints ();
- interp_text_sect_low = interp_text_sect_high = 0;
- interp_plt_sect_low = interp_plt_sect_high = 0;
+ info->interp_text_sect_low = info->interp_text_sect_high = 0;
+ info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
@@ -1308,18 +1270,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_text_sect_high =
- interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_text_sect_high =
+ info->interp_text_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
- interp_plt_sect_low =
+ info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_plt_sect_high =
- interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
create_solib_event_breakpoint (target_gdbarch, sym_addr);
@@ -1412,18 +1376,20 @@ enable_break (struct svr4_info *info)
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
- interp_text_sect_low =
+ info->interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_text_sect_high =
- interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_text_sect_high =
+ info->interp_text_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
if (interp_sect)
{
- interp_plt_sect_low =
+ info->interp_plt_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
- interp_plt_sect_high =
- interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+ info->interp_plt_sect_high =
+ info->interp_plt_sect_low
+ + bfd_section_size (tmp_bfd, interp_sect);
}
/* Now try to set a breakpoint in the dynamic linker. */
@@ -1686,7 +1652,7 @@ svr4_solib_create_inferior_hook (void)
struct thread_info *tp;
struct svr4_info *info;
- info = get_svr4_info (PIDGET (inferior_ptid));
+ info = get_svr4_info ();
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -1726,7 +1692,14 @@ svr4_solib_create_inferior_hook (void)
static void
svr4_clear_solib (void)
{
- remove_svr4_info (PIDGET (inferior_ptid));
+ struct svr4_info *info;
+
+ info = get_svr4_info ();
+ info->debug_base = 0;
+ info->debug_loader_offset_p = 0;
+ info->debug_loader_offset = 0;
+ xfree (info->debug_loader_name);
+ info->debug_loader_name = NULL;
}
static void
@@ -1925,6 +1898,8 @@ void
_initialize_svr4_solib (void)
{
solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init);
+ solib_svr4_sspace_data
+ = register_symbol_space_data_with_cleanup (svr4_sspace_data_cleanup);
svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
svr4_so_ops.free_so = svr4_free_so;
@@ -1937,6 +1912,4 @@ _initialize_svr4_solib (void)
svr4_so_ops.bfd_open = solib_bfd_open;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
-
- observer_attach_inferior_exit (solib_svr4_inferior_exit);
}
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/printcmd.c 2009-09-03 03:02:39.000000000 +0100
@@ -135,16 +135,25 @@ struct display
{
/* Chain link to next auto-display item. */
struct display *next;
+
/* The expression as the user typed it. */
char *exp_string;
+
/* Expression to be evaluated and displayed. */
struct expression *exp;
+
/* Item number of this auto-display item. */
int number;
+
/* Display format specified. */
struct format_data format;
+
+ /* Symbol space associated with `block'. */
+ struct symbol_space *sspace;
+
/* Innermost block required by this expression when evaluated */
struct block *block;
+
/* Status of this display (enabled or disabled) */
int enabled_p;
};
@@ -1449,6 +1458,7 @@ display_command (char *exp, int from_tty
new->exp_string = xstrdup (exp);
new->exp = expr;
new->block = innermost_block;
+ new->sspace = current_symbol_space;
new->next = display_chain;
new->number = ++display_number;
new->format = fmt;
@@ -1585,7 +1595,12 @@ do_one_display (struct display *d)
}
if (d->block)
- within_current_scope = contained_in (get_selected_block (0), d->block);
+ {
+ if (d->sspace == current_symbol_space)
+ within_current_scope = contained_in (get_selected_block (0), d->block);
+ else
+ within_current_scope = 0;
+ }
else
within_current_scope = 1;
if (!within_current_scope)
@@ -1810,6 +1825,7 @@ display_uses_solib_p (const struct displ
const union exp_element *const elts = exp->elts;
if (d->block != NULL
+ && d->sspace == solib->sspace
&& solib_contains_address_p (solib, d->block->startaddr))
return 1;
@@ -1828,9 +1844,15 @@ display_uses_solib_p (const struct displ
const struct symbol *const symbol = elts[i + 2].symbol;
const struct obj_section *const section =
SYMBOL_OBJ_SECTION (symbol);
+#if 0
+ /* FIXME: this info isn't there yet. */
+ const struct symbol_space *sspace = elts[i + 3].symbol;
+#endif
if (block != NULL
- && solib_contains_address_p (solib, block->startaddr))
+ /* FIXME: && sspace == solib->sspace */
+ && solib_contains_address_p (solib,
+ block->startaddr))
return 1;
if (section && section->objfile == solib->objfile)
Index: src/gdb/linux-fork.c
===================================================================
--- src.orig/gdb/linux-fork.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/linux-fork.c 2009-09-03 03:02:39.000000000 +0100
@@ -41,9 +41,6 @@ static int highest_fork_num;
/* Prevent warning from -Wmissing-prototypes. */
extern void _initialize_linux_fork (void);
-int detach_fork = 1; /* Default behavior is to detach
- newly forked processes (legacy). */
-
/* Fork list data structure: */
struct fork_info
{
@@ -648,14 +645,6 @@ _initialize_linux_fork (void)
{
init_fork_list ();
- /* Set/show detach-on-fork: user-settable mode. */
-
- add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
-Set whether gdb will detach the child of a fork."), _("\
-Show whether gdb will detach the child of a fork."), _("\
-Tells gdb whether to detach the child of a fork."),
- NULL, NULL, &setlist, &showlist);
-
/* Checkpoint command: create a fork of the inferior process
and set it aside for later debugging. */
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/infrun.c 2009-09-03 03:02:39.000000000 +0100
@@ -109,6 +109,9 @@ int sync_execution = 0;
static ptid_t previous_inferior_ptid;
+/* Default behavior is to detach newly forked processes (legacy). */
+int detach_fork = 1;
+
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
@@ -461,6 +464,200 @@ follow_inferior_reset_breakpoints (void)
insert_breakpoints ();
}
+/* The child has exited or execed: resume threads of the parent the
+ user wanted to be executing. */
+
+static int
+proceed_after_vfork_done (struct thread_info *thread,
+ void *arg)
+{
+ int pid = * (int *) arg;
+
+ if (ptid_get_pid (thread->ptid) == pid
+ && is_running (thread->ptid)
+ && !is_executing (thread->ptid)
+ && !thread->stop_requested
+ && thread->stop_signal == TARGET_SIGNAL_0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resuming vfork parent thread %s\n",
+ target_pid_to_str (thread->ptid));
+
+ switch_to_thread (thread->ptid);
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+
+ return 0;
+}
+
+/* Called whenever we notice an exec or exit event, to handle
+ detaching or resuming a vfork parent. */
+
+static void
+handle_vfork_child_exec_or_exit (int exec)
+{
+ struct inferior *inf = current_inferior ();
+
+ if (inf->vfork_parent)
+ {
+ int resume_parent = -1;
+
+ /* This exec or exit marks the end of the shared memory region
+ between the parent and the child. If the user wanted to
+ detach from the parent, now is the time. */
+
+ if (inf->vfork_parent->pending_detach)
+ {
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+ struct symbol_space *sspace;
+ struct address_space *aspace;
+
+ /* follow-fork child, detach-on-fork on */
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ /* We're letting loose of the parent. */
+ tp = any_live_thread_of_process (inf->vfork_parent->pid);
+ switch_to_thread (tp->ptid);
+
+ /* We're about to detach from the parent, which implicitly
+ removes breakpoints from its address space. There's a
+ catch here: we want to reuse the spaces for the child,
+ but, parent/child are still sharing the sspace at this
+ point, although the exec in reality makes the kernel give
+ the child a fresh set of new pages. The problem here is
+ that the breakpoints module being unaware of this, would
+ likely chose the child process to write to the parent
+ address space. Swapping the child temporarily away from
+ the spaces has the desired effect. Yes, this is "sort
+ of" a hack. */
+
+ sspace = inf->sspace;
+ aspace = inf->aspace;
+ inf->aspace = NULL;
+ inf->sspace = NULL;
+
+ if (debug_infrun || info_verbose)
+ {
+ target_terminal_ours ();
+
+ if (exec)
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exec.\n",
+ inf->vfork_parent->pid);
+ else
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exit.\n",
+ inf->vfork_parent->pid);
+ }
+
+ target_detach (NULL, 0);
+
+ /* Put it back. */
+ inf->sspace = sspace;
+ inf->aspace = aspace;
+
+ do_cleanups (old_chain);
+ }
+ else if (exec)
+ {
+ /* We're staying attached to the parent, so, really give the
+ child a new address space. */
+ inf->sspace = add_symbol_space (maybe_new_address_space ());
+ inf->aspace = inf->sspace->aspace;
+ inf->sspace->removable = 1;
+ set_current_symbol_space (inf->sspace);
+
+ resume_parent = inf->vfork_parent->pid;
+
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+ else
+ {
+ struct cleanup *old_chain;
+ struct symbol_space *sspace;
+
+ /* If this is a vfork child exiting, then the sspace and
+ aspaces where shared with the parent. Since we're
+ reporting the process exit, we'll be mourning all that is
+ found in the address space, and switching to null_ptid,
+ preparing to start a new inferior. But, since we don't
+ want to clobber the parent's address/symbol spaces, we go
+ ahead and create a new one for this exiting inferior.
+ The alternative, is to make normal_stop switch to the
+ parent process automatically, without messing up with the
+ parent's spaces. */
+
+ /* Switch to null_ptid, so that clone_symbol_space doesn't want
+ to read the selected frame of a dead process. */
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = null_ptid;
+
+ /* This inferior is dead, so avoid giving the breakpoints
+ module the option to write through to it (cloning a
+ symbol space resets breakpoints). */
+ inf->aspace = NULL;
+ inf->sspace = NULL;
+ sspace = add_symbol_space (maybe_new_address_space ());
+ set_current_symbol_space (sspace);
+ sspace->removable = 1;
+ clone_symbol_space (sspace, inf->vfork_parent->sspace);
+ inf->sspace = sspace;
+ inf->aspace = sspace->aspace;
+
+ /* Put back inferior_ptid. We'll continue mourning this
+ inferior. */
+ do_cleanups (old_chain);
+
+ resume_parent = inf->vfork_parent->pid;
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+
+ inf->vfork_parent = NULL;
+
+ gdb_assert (current_symbol_space == inf->sspace);
+
+ if (non_stop && resume_parent != -1)
+ {
+ /* If the user wanted the parent to be running, let it go
+ free now. */
+ struct cleanup *old_chain = make_cleanup_restore_current_thread ();
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent process %d\n",
+ resume_parent);
+
+ iterate_over_threads (proceed_after_vfork_done, &resume_parent);
+
+ do_cleanups (old_chain);
+ }
+ }
+}
+
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char follow_exec_mode_replace[] = "replace";
+static const char follow_exec_mode_keep[] = "keep";
+static const char *follow_exec_mode_names[] =
+{
+ follow_exec_mode_replace,
+ follow_exec_mode_keep,
+ NULL,
+};
+
+static const char *follow_exec_mode_string = follow_exec_mode_replace;
+static void
+show_follow_exec_mode_string (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
+}
+
/* EXECD_PATHNAME is assumed to be non-NULL. */
static void
@@ -468,6 +665,7 @@ follow_exec (ptid_t pid, char *execd_pat
{
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
+ struct inferior *inf = current_inferior ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@@ -489,6 +687,9 @@ follow_exec (ptid_t pid, char *execd_pat
that may write the bp's "shadow contents" (the instruction
value that was overwritten witha TRAP instruction). Since
we now have a new a.out, those shadow contents aren't valid. */
+
+ mark_breakpoints_out ();
+
update_breakpoints_after_exec ();
/* If there was one, it's gone now. We cannot truly step-to-next
@@ -506,7 +707,9 @@ follow_exec (ptid_t pid, char *execd_pat
th->stop_requested = 0;
/* What is this a.out's name? */
- printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
+ printf_unfiltered (_("%s is executing new program: %s\n"),
+ target_pid_to_str (inferior_ptid),
+ execd_pathname);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
@@ -525,9 +728,6 @@ follow_exec (ptid_t pid, char *execd_pat
execd_pathname = name;
}
- /* That a.out is now the one to use. */
- exec_file_attach (execd_pathname, 0);
-
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
dld will have had a chance to initialize the child. */
@@ -536,6 +736,25 @@ follow_exec (ptid_t pid, char *execd_pat
previous incarnation of this process. */
no_shared_libraries (NULL, 0);
+ if (follow_exec_mode_string == follow_exec_mode_keep)
+ {
+ struct symbol_space *sspace;
+
+ /* The user wants to keep the old symbol space around. Create a
+ new fresh one, and switch to it. */
+
+ sspace = add_symbol_space (maybe_new_address_space ());
+ sspace->removable = 1;
+ set_current_symbol_space (sspace);
+ inf->sspace = sspace;
+ inf->aspace = sspace->aspace;
+ }
+
+ gdb_assert (current_symbol_space == inf->sspace);
+
+ /* That a.out is now the one to use. */
+ exec_file_attach (execd_pathname, 0);
+
/* Load the main file's symbols. */
symbol_file_add_main (execd_pathname, 0);
@@ -969,6 +1188,7 @@ displaced_step_fixup (ptid_t event_ptid,
struct regcache *regcache;
struct gdbarch *gdbarch;
CORE_ADDR actual_pc;
+ struct address_space *aspace;
head = displaced_step_request_queue;
ptid = head->ptid;
@@ -979,8 +1199,9 @@ displaced_step_fixup (ptid_t event_ptid,
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
+ aspace = get_regcache_aspace (regcache);
- if (breakpoint_here_p (actual_pc))
+ if (breakpoint_here_p (aspace, actual_pc))
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
@@ -1148,6 +1369,7 @@ resume (int step, enum target_signal sig
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
QUIT;
@@ -1173,7 +1395,7 @@ resume (int step, enum target_signal sig
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
- if (breakpoint_here_p (pc) == permanent_breakpoint_here)
+ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
@@ -1287,7 +1509,7 @@ a command like `return' or `jump' to con
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
- if (step && breakpoint_inserted_here_p (pc))
+ if (step && breakpoint_inserted_here_p (aspace, pc))
step = 0;
}
@@ -1361,23 +1583,26 @@ clear_proceed_status_callback (struct th
void
clear_proceed_status (void)
{
+ if (!non_stop)
+ {
+ /* In all-stop mode, delete the per-thread status of all
+ threads, even if inferior_ptid is null_ptid, there may be
+ threads on the list. E.g., we may be launching a new
+ process, while selecting the executable. */
+ iterate_over_threads (clear_proceed_status_callback, NULL);
+ }
+
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inferior;
if (non_stop)
{
- /* If in non-stop mode, only delete the per-thread status
- of the current thread. */
+ /* If in non-stop mode, only delete the per-thread status of
+ the current thread. */
clear_proceed_status_thread (inferior_thread ());
}
- else
- {
- /* In all-stop mode, delete the per-thread status of
- *all* threads. */
- iterate_over_threads (clear_proceed_status_callback, NULL);
- }
-
+
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
}
@@ -1439,7 +1664,8 @@ prepare_to_proceed (int step)
{
struct regcache *regcache = get_thread_regcache (wait_ptid);
- if (breakpoint_here_p (regcache_read_pc (regcache)))
+ if (breakpoint_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache)))
{
/* If stepping, remember current thread to switch back to. */
if (step)
@@ -1477,6 +1703,7 @@ proceed (CORE_ADDR addr, enum target_sig
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
+ struct address_space *aspace;
int oneproc = 0;
/* If we're stopped at a fork/vfork, follow the branch set by the
@@ -1491,6 +1718,7 @@ proceed (CORE_ADDR addr, enum target_sig
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
+ aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);
if (step > 0)
@@ -1500,7 +1728,7 @@ proceed (CORE_ADDR addr, enum target_sig
if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc && breakpoint_here_p (pc)
+ if (pc == stop_pc && breakpoint_here_p (aspace, pc)
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
step one instruction before inserting breakpoints so that
@@ -2227,6 +2455,7 @@ adjust_pc_after_break (struct execution_
{
struct regcache *regcache;
struct gdbarch *gdbarch;
+ struct address_space *aspace;
CORE_ADDR breakpoint_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
@@ -2292,6 +2521,8 @@ adjust_pc_after_break (struct execution_
if (gdbarch_decr_pc_after_break (gdbarch) == 0)
return;
+ aspace = get_regcache_aspace (regcache);
+
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
@@ -2305,8 +2536,8 @@ adjust_pc_after_break (struct execution_
already queued and arrive later. To suppress those spurious
SIGTRAPs, we keep a list of such breakpoint locations for a bit,
and retire them after a number of stop events are reported. */
- if (software_breakpoint_inserted_here_p (breakpoint_pc)
- || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
+ if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
@@ -2559,6 +2790,8 @@ handle_inferior_event (struct execution_
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
inferior_ptid = ecs->ptid;
+ set_current_symbol_space (current_inferior ()->sspace);
+ handle_vfork_child_exec_or_exit (0);
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);
@@ -2577,6 +2810,8 @@ handle_inferior_event (struct execution_
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
inferior_ptid = ecs->ptid;
+ set_current_symbol_space (current_inferior ()->sspace);
+ handle_vfork_child_exec_or_exit (0);
stop_print_frame = 0;
target_terminal_ours (); /* Must do this before mourn anyway */
@@ -2633,19 +2868,45 @@ handle_inferior_event (struct execution_
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
+ ptid_t parent;
+ ptid_t child;
int should_resume;
+ int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
should_resume = follow_fork ();
+ parent = ecs->ptid;
+ child = ecs->ws.value.related_pid;
+
+ /* In non-stop mode, also resume the other branch. */
+ if (non_stop && !detach_fork)
+ {
+ if (follow_child)
+ switch_to_thread (parent);
+ else
+ switch_to_thread (child);
+
+ ecs->event_thread = inferior_thread ();
+ ecs->ptid = inferior_ptid;
+ keep_going (ecs);
+ }
+
+ if (follow_child)
+ switch_to_thread (child);
+ else
+ switch_to_thread (parent);
+
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;
@@ -2658,6 +2919,22 @@ handle_inferior_event (struct execution_
ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
+ case TARGET_WAITKIND_VFORK_DONE:
+ /* Done with the shared memory region. Re-insert breakpoints in
+ the parent, and keep going. */
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORK_DONE\n");
+
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ context_switch (ecs->ptid);
+
+ current_inferior ()->waiting_for_vfork_done = 0;
+ /* This also takes care of reinserting breakpoints in the
+ previously locked inferior. */
+ keep_going (ecs);
+ return;
+
case TARGET_WAITKIND_EXECD:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
@@ -2670,12 +2947,17 @@ handle_inferior_event (struct execution_
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Do whatever is necessary to the parent branch of the vfork. */
+ handle_vfork_child_exec_or_exit (1);
+
/* This causes the eventpoints and symbol table to be reset.
Must do this now, before trying to determine whether to
stop. */
follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* Note that this may be referenced from inside
@@ -2880,14 +3162,15 @@ targets should add new threads to the th
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
+ struct address_space *aspace = get_regcache_aspace (get_current_regcache ());
/* Check if a regular breakpoint has been hit before checking
for a potential single step breakpoint. Otherwise, GDB will
not see this breakpoint hit when stepping onto breakpoints. */
- if (regular_breakpoint_inserted_here_p (stop_pc))
+ if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
{
ecs->random_signal = 0;
- if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
thread_hop_needed = 1;
}
else if (singlestep_breakpoints_inserted_p)
@@ -3174,7 +3457,8 @@ targets should add new threads to the th
non-standard signals can't be explained by the breakpoint. */
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
|| (! ecs->event_thread->trap_expected
- && breakpoint_inserted_here_p (stop_pc)
+ && breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()),
+ stop_pc)
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
@@ -3231,8 +3515,10 @@ targets should add new threads to the th
}
/* See if there is a breakpoint at the current PC. */
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
+
/* Following in case break condition called a
function. */
stop_print_frame = 1;
@@ -3763,6 +4049,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
+ sr_sal.sspace = get_frame_symbol_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
@@ -3861,8 +4148,9 @@ infrun: not switching back to stepped th
/* Normal function call return (static or dynamic). */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ sr_sal.sspace = get_frame_symbol_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
}
else
insert_step_resume_breakpoint_at_caller (frame);
@@ -3887,6 +4175,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.sspace = get_frame_symbol_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
@@ -3933,6 +4222,7 @@ infrun: not switching back to stepped th
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.sspace = get_frame_symbol_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
}
@@ -3998,6 +4288,7 @@ infrun: not switching back to stepped th
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = get_frame_symbol_space (frame);
/* Do not specify what the fp should be when we stop since
on some machines the prologue is where the new fp value
@@ -4277,6 +4568,7 @@ handle_step_into_function (struct gdbarc
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ sr_sal.sspace = get_frame_symbol_space (get_current_frame ());
/* Do not specify what the fp should be when we stop since on
some machines the prologue is where the new fp value is
@@ -4368,6 +4660,7 @@ insert_step_resume_breakpoint_at_frame (
gdbarch = get_frame_arch (return_frame);
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = get_frame_symbol_space (return_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
get_stack_frame_id (return_frame));
@@ -4404,6 +4697,7 @@ insert_step_resume_breakpoint_at_caller
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
frame_unwind_caller_pc (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.sspace = frame_unwind_symbol_space (next_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
frame_unwind_caller_id (next_frame));
@@ -4907,6 +5201,11 @@ done:
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
}
+
+ /* Try to get rid of automatically added symbol spaces that are no
+ longer needed. Keeping those around slows down things linearly.
+ Note that this never removes the current symbol space. */
+ prune_symbol_spaces ();
}
static int
@@ -5959,6 +6258,25 @@ By default, the debugger will follow the
show_follow_fork_mode_string,
&setlist, &showlist);
+ add_setshow_enum_cmd ("follow-exec-mode", class_run,
+ follow_exec_mode_names,
+ &follow_exec_mode_string, _("\
+Set debugger response to a program call of exec."), _("\
+Show debugger response to a program call of exec."), _("\
+An exec call replaces the process'es program image. follow-exec-mode can be:\n\
+\n\
+ keep - The previous symbol space is kept so that it can\n\
+be restarted afterwards. The process is assigned a new symbol space.\n\
+\n\
+ replace - the process'es previous symbol space is reused. The new\n\
+executable replaces the previous executable in the symbol space.\n\
+\n\
+By default, the debugger will reuse the symbol space, replacing its main\n\
+executable."),
+ NULL,
+ show_follow_exec_mode_string,
+ &setlist, &showlist);
+
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
@@ -6017,6 +6335,14 @@ Options are 'forward' or 'reverse'."),
set_exec_direction_func, show_exec_direction_func,
&setlist, &showlist);
+ /* Set/show detach-on-fork: user-settable mode. */
+
+ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
+Set whether gdb will detach the child of a fork."), _("\
+Show whether gdb will detach the child of a fork."), _("\
+Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);
Index: src/gdb/regcache.h
===================================================================
--- src.orig/gdb/regcache.h 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/regcache.h 2009-09-03 03:02:39.000000000 +0100
@@ -23,6 +23,7 @@
struct regcache;
struct gdbarch;
+struct address_space;
extern struct regcache *get_current_regcache (void);
extern struct regcache *get_thread_regcache (ptid_t ptid);
@@ -36,6 +37,10 @@ struct regcache *regcache_xmalloc (struc
extern struct gdbarch *get_regcache_arch (const struct regcache *regcache);
+/* Return REGCACHE's address space. */
+
+extern struct address_space *get_regcache_aspace (const struct regcache *regcache);
+
/* Transfer a raw register [0..NUM_REGS) between core-gdb and the
regcache. */
Index: src/gdb/regcache.c
===================================================================
--- src.orig/gdb/regcache.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/regcache.c 2009-09-03 03:02:39.000000000 +0100
@@ -185,6 +185,11 @@ register_size (struct gdbarch *gdbarch,
struct regcache
{
struct regcache_descr *descr;
+
+ /* The address space of this register cache (for registers where it
+ makes sense, like PC or SP). */
+ struct address_space *aspace;
+
/* The register buffers. A read-only register cache can hold the
full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) while a read/write
register cache can only hold [0 .. gdbarch_num_regs). */
@@ -219,6 +224,7 @@ regcache_xmalloc (struct gdbarch *gdbarc
= XCALLOC (descr->sizeof_raw_registers, gdb_byte);
regcache->register_valid_p
= XCALLOC (descr->sizeof_raw_register_valid_p, gdb_byte);
+ regcache->aspace = NULL;
regcache->readonly_p = 1;
regcache->ptid = minus_one_ptid;
return regcache;
@@ -254,6 +260,12 @@ get_regcache_arch (const struct regcache
return regcache->descr->gdbarch;
}
+struct address_space *
+get_regcache_aspace (const struct regcache *regcache)
+{
+ return regcache->aspace;
+}
+
/* Return a pointer to register REGNUM's buffer cache. */
static gdb_byte *
@@ -340,10 +352,14 @@ regcache_cpy (struct regcache *dst, stru
{
int i;
gdb_byte *buf;
+
gdb_assert (src != NULL && dst != NULL);
gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
gdb_assert (src != dst);
gdb_assert (src->readonly_p || dst->readonly_p);
+
+ dst->aspace = src->aspace;
+
if (!src->readonly_p)
regcache_save (dst, do_cooked_read, src);
else if (!dst->readonly_p)
@@ -362,6 +378,8 @@ regcache_cpy_no_passthrough (struct regc
move of data into the current regcache. Doing this would be
silly - it would mean that valid_p would be completely invalid. */
gdb_assert (dst->readonly_p);
+
+ dst->aspace = src->aspace;
memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
memcpy (dst->register_valid_p, src->register_valid_p,
dst->descr->sizeof_raw_register_valid_p);
@@ -438,6 +456,8 @@ get_thread_arch_regcache (ptid_t ptid, s
new_regcache = regcache_xmalloc (gdbarch);
new_regcache->readonly_p = 0;
new_regcache->ptid = ptid;
+ new_regcache->aspace = target_thread_address_space (ptid);
+ gdb_assert (new_regcache->aspace != NULL);
list = xmalloc (sizeof (struct regcache_list));
list->regcache = new_regcache;
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/infcall.c 2009-09-03 03:02:39.000000000 +0100
@@ -730,6 +730,7 @@ call_function_by_hand (struct value *fun
struct breakpoint *bpt;
struct symtab_and_line sal;
init_sal (&sal); /* initialize to zeroes */
+ sal.sspace = current_symbol_space;
sal.pc = bp_addr;
sal.section = find_pc_overlay (sal.pc);
/* Sanity. The exact same SP value is returned by
Index: src/gdb/arch-utils.c
===================================================================
--- src.orig/gdb/arch-utils.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/arch-utils.c 2009-09-03 03:02:39.000000000 +0100
@@ -751,6 +751,14 @@ get_current_arch (void)
return target_gdbarch;
}
+int
+default_has_shared_address_space (struct gdbarch *gdbarch)
+{
+ /* Simply say no. In most unix-like targets each inferior/process
+ has its own address space. */
+ return 0;
+}
+
/* */
extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
Index: src/gdb/arch-utils.h
===================================================================
--- src.orig/gdb/arch-utils.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/arch-utils.h 2009-09-03 03:02:39.000000000 +0100
@@ -148,4 +148,6 @@ extern struct gdbarch *gdbarch_from_bfd
routines to determine the architecture to execute a command in. */
extern struct gdbarch *get_current_arch (void);
+extern int default_has_shared_address_space (struct gdbarch *);
+
#endif
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gdbarch.sh 2009-09-03 03:02:39.000000000 +0100
@@ -736,6 +736,9 @@ v:int:has_global_solist:::0:0::0
# visible to all address spaces automatically. For such cases,
# this property should be set to true.
v:int:has_global_breakpoints:::0:0::0
+
+# True if inferiors share an address space (e.g., uClinux).
+m:int:has_shared_address_space:void:::default_has_shared_address_space::0
EOF
}
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gdbarch.h 2009-09-03 03:02:39.000000000 +0100
@@ -870,6 +870,12 @@ extern void set_gdbarch_has_global_solis
extern int gdbarch_has_global_breakpoints (struct gdbarch *gdbarch);
extern void set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch, int has_global_breakpoints);
+/* True if inferiors share an address space (e.g., uClinux). */
+
+typedef int (gdbarch_has_shared_address_space_ftype) (struct gdbarch *gdbarch);
+extern int gdbarch_has_shared_address_space (struct gdbarch *gdbarch);
+extern void set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch, gdbarch_has_shared_address_space_ftype *has_shared_address_space);
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gdbarch.c 2009-09-03 03:02:39.000000000 +0100
@@ -246,6 +246,7 @@ struct gdbarch
gdbarch_record_special_symbol_ftype *record_special_symbol;
int has_global_solist;
int has_global_breakpoints;
+ gdbarch_has_shared_address_space_ftype *has_shared_address_space;
};
@@ -383,6 +384,7 @@ struct gdbarch startup_gdbarch =
0, /* record_special_symbol */
0, /* has_global_solist */
0, /* has_global_breakpoints */
+ default_has_shared_address_space, /* has_shared_address_space */
/* startup_gdbarch() */
};
@@ -465,6 +467,7 @@ gdbarch_alloc (const struct gdbarch_info
gdbarch->displaced_step_location = NULL;
gdbarch->target_signal_from_host = default_target_signal_from_host;
gdbarch->target_signal_to_host = default_target_signal_to_host;
+ gdbarch->has_shared_address_space = default_has_shared_address_space;
/* gdbarch_alloc() */
return gdbarch;
@@ -639,6 +642,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of record_special_symbol, has predicate */
/* Skip verify of has_global_solist, invalid_p == 0 */
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
+ /* Skip verify of has_shared_address_space, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length);
make_cleanup (xfree, buf);
if (length > 0)
@@ -872,6 +876,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
+ "gdbarch_dump: has_shared_address_space = <%s>\n",
+ host_address_to_string (gdbarch->has_shared_address_space));
+ fprintf_unfiltered (file,
"gdbarch_dump: have_nonsteppable_watchpoint = %s\n",
plongest (gdbarch->have_nonsteppable_watchpoint));
fprintf_unfiltered (file,
@@ -3414,6 +3421,23 @@ set_gdbarch_has_global_breakpoints (stru
gdbarch->has_global_breakpoints = has_global_breakpoints;
}
+int
+gdbarch_has_shared_address_space (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->has_shared_address_space != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_has_shared_address_space called\n");
+ return gdbarch->has_shared_address_space (gdbarch);
+}
+
+void
+set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch,
+ gdbarch_has_shared_address_space_ftype has_shared_address_space)
+{
+ gdbarch->has_shared_address_space = has_shared_address_space;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
Index: src/gdb/linux-tdep.c
===================================================================
--- src.orig/gdb/linux-tdep.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/linux-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -22,8 +22,10 @@
#include "gdbtypes.h"
#include "linux-tdep.h"
#include "observer.h"
-
+#include "auxv.h"
+#include "target.h"
#include "elf-bfd.h"
+#include "elf/common.h"
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
@@ -139,6 +141,21 @@ linux_get_siginfo_type (struct gdbarch *
return siginfo_type;
}
+int
+linux_has_shared_address_space (void)
+{
+ /* Determine whether we are running on uClinux or normal Linux
+ kernel. */
+ CORE_ADDR dummy;
+ int target_is_uclinux;
+
+ target_is_uclinux
+ = (target_auxv_search (¤t_target, AT_NULL, &dummy) > 0
+ && target_auxv_search (¤t_target, AT_PAGESZ, &dummy) == 0);
+
+ return target_is_uclinux;
+}
+
/* Observer for the executable_changed event, to check whether the new
exec binary is a PIE (Position Independent Executable) specimen, which
is currently unsupported. */
@@ -160,6 +177,9 @@ GDB does NOT currently support. Most de
in this session.\n"));
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_linux_tdep;
+
void
_initialize_linux_tdep (void)
{
Index: src/gdb/arm-tdep.c
===================================================================
--- src.orig/gdb/arm-tdep.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/arm-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -2594,13 +2594,14 @@ int
arm_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
/* NOTE: This may insert the wrong breakpoint instruction when
single-stepping over a mode-changing instruction, if the
CPSR heuristics are used. */
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
Index: src/gdb/arm-linux-tdep.c
===================================================================
--- src.orig/gdb/arm-linux-tdep.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/arm-linux-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -586,6 +586,7 @@ static int
arm_linux_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
/* The Linux kernel offers some user-mode helpers in a high page. We can
@@ -596,7 +597,7 @@ arm_linux_software_single_step (struct f
if (next_pc > 0xffff0000)
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
Index: src/gdb/cris-tdep.c
===================================================================
--- src.orig/gdb/cris-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/cris-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -471,7 +471,7 @@ crisv32_single_step_through_delay (struc
{
/* In delay slot - check if there's a breakpoint at the preceding
instruction. */
- if (breakpoint_here_p (erp & ~0x1))
+ if (breakpoint_here_p (get_frame_address_space (this_frame), erp & ~0x1))
ret = 1;
}
return ret;
@@ -2132,6 +2132,7 @@ static int
cris_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
inst_env_type inst_env;
/* Analyse the present instruction environment and insert
@@ -2149,13 +2150,14 @@ cris_software_single_step (struct frame_
and possibly another one for a branch, jump, etc. */
CORE_ADDR next_pc
= (CORE_ADDR) inst_env.reg[gdbarch_pc_regnum (gdbarch)];
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
if (inst_env.branch_found
&& (CORE_ADDR) inst_env.branch_break_address != next_pc)
{
CORE_ADDR branch_target_address
= (CORE_ADDR) inst_env.branch_break_address;
- insert_single_step_breakpoint (gdbarch, branch_target_address);
+ insert_single_step_breakpoint (gdbarch,
+ aspace, branch_target_address);
}
}
Index: src/gdb/mips-tdep.c
===================================================================
--- src.orig/gdb/mips-tdep.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/mips-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -2383,7 +2383,8 @@ mips_addr_bits_remove (struct gdbarch *g
the sequence. */
static int
-deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
+deal_with_atomic_sequence (struct gdbarch *gdbarch,
+ struct address_space *aspace, CORE_ADDR pc)
{
CORE_ADDR breaks[2] = {-1, -1};
CORE_ADDR loc = pc;
@@ -2471,7 +2472,7 @@ deal_with_atomic_sequence (struct gdbarc
/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
- insert_single_step_breakpoint (gdbarch, breaks[index]);
+ insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
return 1;
}
@@ -2485,15 +2486,16 @@ int
mips_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR pc, next_pc;
pc = get_frame_pc (frame);
- if (deal_with_atomic_sequence (gdbarch, pc))
+ if (deal_with_atomic_sequence (gdbarch, aspace, pc))
return 1;
next_pc = mips_next_pc (frame, pc);
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
@@ -4677,7 +4679,7 @@ mips_single_step_through_delay (struct g
if (mips_pc_is_mips16 (pc))
return 0;
- if (!breakpoint_here_p (pc + 4))
+ if (!breakpoint_here_p (get_frame_address_space (frame), pc + 4))
return 0;
if (!safe_frame_unwind_memory (frame, pc, buf, sizeof buf))
Index: src/gdb/rs6000-aix-tdep.c
===================================================================
--- src.orig/gdb/rs6000-aix-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/rs6000-aix-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -671,6 +671,7 @@ static int
rs6000_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int ii, insn;
CORE_ADDR loc;
@@ -697,7 +698,7 @@ rs6000_software_single_step (struct fram
/* ignore invalid breakpoint. */
if (breaks[ii] == -1)
continue;
- insert_single_step_breakpoint (gdbarch, breaks[ii]);
+ insert_single_step_breakpoint (gdbarch, aspace, breaks[ii]);
}
errno = 0; /* FIXME, don't ignore errors! */
Index: src/gdb/rs6000-tdep.c
===================================================================
--- src.orig/gdb/rs6000-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/rs6000-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -1075,6 +1075,7 @@ int
ppc_deal_with_atomic_sequence (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR pc = get_frame_pc (frame);
CORE_ADDR breaks[2] = {-1, -1};
@@ -1148,7 +1149,7 @@ ppc_deal_with_atomic_sequence (struct fr
/* Effectively inserts the breakpoints. */
for (index = 0; index <= last_breakpoint; index++)
- insert_single_step_breakpoint (gdbarch, breaks[index]);
+ insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
return 1;
}
Index: src/gdb/solib-irix.c
===================================================================
--- src.orig/gdb/solib-irix.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/solib-irix.c 2009-09-03 03:02:39.000000000 +0100
@@ -365,10 +365,14 @@ disable_break (void)
static int
enable_break (void)
{
- if (symfile_objfile != NULL)
+ if (symfile_objfile != NULL && has_stack_frames ())
{
+ struct frame_info *frame = get_current_frame ();
+ struct address_space *aspace = get_frame_address_space (frame);
+
base_breakpoint
= deprecated_insert_raw_breakpoint (target_gdbarch,
+ aspace,
entry_point_address ());
if (base_breakpoint != NULL)
Index: src/gdb/sparc-tdep.c
===================================================================
--- src.orig/gdb/sparc-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/sparc-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -1312,6 +1312,7 @@ sparc_software_single_step (struct frame
{
struct gdbarch *arch = get_frame_arch (frame);
struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
+ struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR npc, nnpc;
CORE_ADDR pc, orig_npc;
@@ -1322,10 +1323,10 @@ sparc_software_single_step (struct frame
/* Analyze the instruction at PC. */
nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
if (npc != 0)
- insert_single_step_breakpoint (arch, npc);
+ insert_single_step_breakpoint (arch, aspace, npc);
if (nnpc != 0)
- insert_single_step_breakpoint (arch, nnpc);
+ insert_single_step_breakpoint (arch, aspace, nnpc);
/* Assert that we have set at least one breakpoint, and that
they're not set at the same spot - unless we're going
Index: src/gdb/spu-tdep.c
===================================================================
--- src.orig/gdb/spu-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/spu-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -1504,6 +1504,7 @@ static int
spu_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR pc, next_pc;
unsigned int insn;
@@ -1524,7 +1525,8 @@ spu_software_single_step (struct frame_i
else
next_pc = (SPUADDR_ADDR (pc) + 4) & (SPU_LS_SIZE - 1);
- insert_single_step_breakpoint (gdbarch, SPUADDR (SPUADDR_SPU (pc), next_pc));
+ insert_single_step_breakpoint (gdbarch,
+ aspace, SPUADDR (SPUADDR_SPU (pc), next_pc));
if (is_branch (insn, &offset, ®))
{
@@ -1540,7 +1542,7 @@ spu_software_single_step (struct frame_i
target = target & (SPU_LS_SIZE - 1);
if (target != next_pc)
- insert_single_step_breakpoint (gdbarch,
+ insert_single_step_breakpoint (gdbarch, aspace,
SPUADDR (SPUADDR_SPU (pc), target));
}
Index: src/gdb/alpha-tdep.c
===================================================================
--- src.orig/gdb/alpha-tdep.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/alpha-tdep.c 2009-09-03 03:02:39.000000000 +0100
@@ -1489,12 +1489,13 @@ int
alpha_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR pc, next_pc;
pc = get_frame_pc (frame);
next_pc = alpha_next_pc (frame, pc);
- insert_single_step_breakpoint (gdbarch, next_pc);
+ insert_single_step_breakpoint (gdbarch, aspace, next_pc);
return 1;
}
Index: src/gdb/record.c
===================================================================
--- src.orig/gdb/record.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/record.c 2009-09-03 03:02:39.000000000 +0100
@@ -612,15 +612,18 @@ record_wait (struct target_ops *ops,
if (status->kind == TARGET_WAITKIND_STOPPED
&& status->value.sig == TARGET_SIGNAL_TRAP)
{
+ struct regcache *regcache;
+
/* Check if there is a breakpoint. */
registers_changed ();
- tmp_pc = regcache_read_pc (get_current_regcache ());
- if (breakpoint_inserted_here_p (tmp_pc))
+ regcache = get_current_regcache ();
+ tmp_pc = regcache_read_pc (regcache);
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
/* There is a breakpoint. */
- CORE_ADDR decr_pc_after_break =
- gdbarch_decr_pc_after_break
- (get_regcache_arch (get_current_regcache ()));
+ CORE_ADDR decr_pc_after_break
+ = gdbarch_decr_pc_after_break (get_regcache_arch (regcache));
if (decr_pc_after_break)
{
regcache_write_pc (get_thread_regcache (ret),
@@ -663,7 +666,8 @@ record_wait (struct target_ops *ops,
if (execution_direction == EXEC_FORWARD)
{
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (tmp_pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@@ -810,7 +814,8 @@ record_wait (struct target_ops *ops,
/* check breakpoint */
tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (tmp_pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ tmp_pc))
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
Index: src/gdb/fork-child.c
===================================================================
--- src.orig/gdb/fork-child.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/fork-child.c 2009-09-03 03:02:39.000000000 +0100
@@ -138,6 +138,7 @@ fork_inferior (char *exec_file_arg, char
int shell = 0;
static char **argv;
const char *inferior_io_terminal = get_inferior_io_terminal ();
+ struct inferior *inf;
/* If no exec file handed to us, get it from the exec-file command
-- with a good, common error message if none is specified. */
@@ -395,7 +396,10 @@ fork_inferior (char *exec_file_arg, char
if (!have_inferiors ())
init_thread_list ();
- add_inferior (pid);
+ inf = add_inferior (pid);
+
+ inf->aspace = current_symbol_space->aspace;
+ inf->sspace = current_symbol_space;
/* Needed for wait_for_inferior stuff below. */
inferior_ptid = pid_to_ptid (pid);
Index: src/gdb/inf-ptrace.c
===================================================================
--- src.orig/gdb/inf-ptrace.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/inf-ptrace.c 2009-09-03 03:02:39.000000000 +0100
@@ -67,6 +67,8 @@ inf_ptrace_follow_fork (struct target_op
child_inf = add_inferior (fpid);
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
+ inf->sspace = parent_inf->sspace;
+ inf->aspace = parent_inf->aspace;
/* Before detaching from the parent, remove all breakpoints from
it. */
@@ -226,6 +228,8 @@ inf_ptrace_attach (struct target_ops *op
inferior_ptid = pid_to_ptid (pid);
inf = add_inferior (pid);
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
inf->attach_flag = 1;
/* Always add a main thread. If some target extends the ptrace
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/linux-nat.c 2009-09-03 03:02:39.000000000 +0100
@@ -55,6 +55,7 @@
#include "xml-support.h"
#include "terminal.h"
#include <sys/vfs.h>
+#include "solib.h"
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
@@ -601,24 +602,45 @@ linux_child_follow_fork (struct target_o
if (!detach_fork)
linux_enable_event_reporting (pid_to_ptid (child_pid));
+ if (has_vforked
+ && !non_stop /* Non-stop always resumes both branches. */
+ && (!target_is_async_p () || sync_execution)
+ && !(follow_child || detach_fork || sched_multi))
+ {
+ /* The parent stays blocked inside the vfork syscall until the
+ child execs or exits. If we don't let the child run, then
+ the parent stays blocked. If we're telling the parent to run
+ in the foreground, the user will not be able to ctrl-c to get
+ back the terminal, effectively hanging the debug session. */
+ fprintf_filtered (gdb_stderr, _("\
+Can not resume the parent process over vfork in the foreground while \n\
+holding the child stopped. Try \"set detach-on-fork\" or \
+\"set schedule-multiple\".\n"));
+ return 1;
+ }
+
if (! follow_child)
{
- /* We're already attached to the parent, by default. */
+ struct lwp_info *child_lp = NULL;
- /* Before detaching from the child, remove all breakpoints from
- it. If we forked, then this has already been taken care of
- by infrun.c. If we vforked however, any breakpoint inserted
- in the parent is visible in the child, even those added while
- stopped in a vfork catchpoint. This won't actually modify
- the breakpoint list, but will physically remove the
- breakpoints from the child. This will remove the breakpoints
- from the parent also, but they'll be reinserted below. */
- if (has_vforked)
- detach_breakpoints (child_pid);
+ /* We're already attached to the parent, by default. */
/* Detach new forked process? */
if (detach_fork)
{
+ /* Before detaching from the child, remove all breakpoints
+ from it. If we forked, then this has already been taken
+ care of by infrun.c. If we vforked however, any
+ breakpoint inserted in the parent is visible in the
+ child, even those added while stopped in a vfork
+ catchpoint. This will remove the breakpoints from the
+ parent also, but they'll be reinserted below. */
+ if (has_vforked)
+ {
+ /* keep breakpoints list in sync. */
+ remove_breakpoints_pid (GET_PID (inferior_ptid));
+ }
+
if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
@@ -632,7 +654,6 @@ linux_child_follow_fork (struct target_o
else
{
struct inferior *parent_inf, *child_inf;
- struct lwp_info *lp;
struct cleanup *old_chain;
/* Add process to GDB's tables. */
@@ -643,12 +664,47 @@ linux_child_follow_fork (struct target_o
copy_terminal_info (child_inf, parent_inf);
old_chain = save_inferior_ptid ();
+ save_current_symbol_space ();
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
- lp = add_lwp (inferior_ptid);
- lp->stopped = 1;
+ child_lp = add_lwp (inferior_ptid);
+ child_lp->stopped = 1;
+ child_lp->resumed = 1;
+
+ /* If this is a vfork child, then the address-space is
+ shared with the parent. */
+ if (has_vforked)
+ {
+ child_inf->sspace = parent_inf->sspace;
+ child_inf->aspace = parent_inf->aspace;
+ /* The parent will be frozen until the child is done
+ with the shared region. Keep track of the
+ parent. */
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = 0;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->sspace = add_symbol_space (child_inf->aspace);
+ child_inf->sspace->removable = 1;
+ set_current_symbol_space (child_inf->sspace);
+ clone_symbol_space (child_inf->sspace, parent_inf->sspace);
+
+ /* Let the shared library layer (solib-svr4) learn about
+ this new process, relocate the cloned exec, pull in
+ shared libraries, and install the solib event
+ breakpoint. If a "cloned-VM" event was propagated
+ better throughout the core, this wouldn't be
+ required. */
+ solib_create_inferior_hook ();
+ }
+
+ /* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
do_cleanups (old_chain);
@@ -656,16 +712,34 @@ linux_child_follow_fork (struct target_o
if (has_vforked)
{
+ struct lwp_info *lp;
+ struct inferior *parent_inf;
+
+ parent_inf = current_inferior ();
+
+ /* If we detached from the child, then we have to be careful
+ to not insert breakpoints in the parent until the child
+ is done with the shared memory region. However, if we're
+ staying attached to the child, then we can and should
+ insert breakpoints, so that we can debug it. A
+ subsequent child exec or exit is enough to know when does
+ the child stops using the parent's address space. */
+ parent_inf->waiting_for_vfork_done = detach_fork;
+
+ lp = find_lwp_pid (pid_to_ptid (parent_pid));
gdb_assert (linux_supports_tracefork_flag >= 0);
if (linux_supports_tracevforkdone (0))
{
- int status;
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LCFF: waiting for VFORK_DONE on %d\n",
+ parent_pid);
- ptrace (PTRACE_CONT, parent_pid, 0, 0);
- my_waitpid (parent_pid, &status, __WALL);
- if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
- warning (_("Unexpected waitpid result %06x when waiting for "
- "vfork-done"), status);
+ lp->stopped = 1;
+ lp->resumed = 1;
+
+ /* We'll handle the VFORK_DONE event like any other
+ event, in target_wait. */
}
else
{
@@ -700,12 +774,26 @@ linux_child_follow_fork (struct target_o
is only the single-step breakpoint at vfork's return
point. */
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LCFF: no VFORK_DONE support, sleeping a bit\n");
+
usleep (10000);
- }
- /* Since we vforked, breakpoints were removed in the parent
- too. Put them back. */
- reattach_breakpoints (parent_pid);
+ /* Pretend we've seen a PTRACE_EVENT_VFORK_DONE event,
+ and leave it pending. The next linux_nat_resume call
+ will notice a pending event, and bypasses actually
+ resuming the inferior. */
+ lp->status = 0;
+ lp->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
+ lp->stopped = 0;
+ lp->resumed = 1;
+
+ /* If we're in async mode, need to tell the event loop
+ there's something here to process. */
+ if (target_can_async_p ())
+ async_file_mark ();
+ }
}
}
else
@@ -713,16 +801,19 @@ linux_child_follow_fork (struct target_o
struct thread_info *tp;
struct inferior *parent_inf, *child_inf;
struct lwp_info *lp;
-
- /* Before detaching from the parent, remove all breakpoints from it. */
- remove_breakpoints ();
+ struct symbol_space *parent_sspace;
if (info_verbose || debug_linux_nat)
{
target_terminal_ours ();
- fprintf_filtered (gdb_stdlog,
- "Attaching after fork to child process %d.\n",
- child_pid);
+ if (has_vforked)
+ fprintf_filtered (gdb_stdlog, _("\
+Attaching after process %d vfork to child process %d.\n"),
+ parent_pid, child_pid);
+ else
+ fprintf_filtered (gdb_stdlog, _("\
+Attaching after process %d fork to child process %d.\n"),
+ parent_pid, child_pid);
}
/* Add the new inferior first, so that the target_detach below
@@ -734,53 +825,68 @@ linux_child_follow_fork (struct target_o
child_inf->attach_flag = parent_inf->attach_flag;
copy_terminal_info (child_inf, parent_inf);
- /* If we're vforking, we may want to hold on to the parent until
- the child exits or execs. At exec time we can remove the old
- breakpoints from the parent and detach it; at exit time we
- could do the same (or even, sneakily, resume debugging it - the
- child's exec has failed, or something similar).
-
- This doesn't clean up "properly", because we can't call
- target_detach, but that's OK; if the current target is "child",
- then it doesn't need any further cleanups, and lin_lwp will
- generally not encounter vfork (vfork is defined to fork
- in libpthread.so).
-
- The holding part is very easy if we have VFORKDONE events;
- but keeping track of both processes is beyond GDB at the
- moment. So we don't expose the parent to the rest of GDB.
- Instead we quietly hold onto it until such time as we can
- safely resume it. */
+ parent_sspace = parent_inf->sspace;
+
+ /* If we're vforking, we want to hold on to the parent until the
+ child exits or execs. At child exec or exit time we can
+ remove the old breakpoints from the parent and detach or
+ resume it. Otherwise, detach the parent now; we'll want to
+ reuse it's symbol/address spaces, but we can't set them to
+ the child before removing breakpoints from the parent,
+ otherwise, the breakpoints module could decide to remove
+ breakpoints from the wrong process (since they'd be assigned
+ to the same address space). */
if (has_vforked)
{
- struct lwp_info *parent_lwp;
-
- linux_parent_pid = parent_pid;
-
- /* Get rid of the inferior on the core side as well. */
- inferior_ptid = null_ptid;
- detach_inferior (parent_pid);
-
- /* Also get rid of all its lwps. We will detach from this
- inferior soon-ish, but, we will still get an exit event
- reported through waitpid when it exits. If we didn't get
- rid of the lwps from our list, we would end up reporting
- the inferior exit to the core, which would then try to
- mourn a non-existing (from the core's perspective)
- inferior. */
- parent_lwp = find_lwp_pid (pid_to_ptid (parent_pid));
- purge_lwp_list (GET_PID (parent_lwp->ptid));
- linux_parent_pid = parent_pid;
+ gdb_assert (child_inf->vfork_parent == NULL);
+ gdb_assert (parent_inf->vfork_child == NULL);
+ child_inf->vfork_parent = parent_inf;
+ child_inf->pending_detach = 0;
+ parent_inf->vfork_child = child_inf;
+ parent_inf->pending_detach = detach_fork;
+ parent_inf->waiting_for_vfork_done = 0;
}
else if (detach_fork)
target_detach (NULL, 0);
+ /* Note that the detach above makes PARENT_INF dangling. */
+
+ /* Add the child thread to the appropriate lists, and switch to
+ this new thread, before cloning the symbol space, and
+ informing the solib layer about this new process. */
+
inferior_ptid = ptid_build (child_pid, child_pid, 0);
add_thread (inferior_ptid);
lp = add_lwp (inferior_ptid);
lp->stopped = 1;
+ lp->resumed = 1;
+
+ /* If this is a vfork child, then the address-space is shared
+ with the parent. If we detached from the parent, then we can
+ reuse the parent's symbol/address spaces. */
+ if (has_vforked || detach_fork)
+ {
+ child_inf->sspace = parent_sspace;
+ child_inf->aspace = child_inf->sspace->aspace;
+ }
+ else
+ {
+ child_inf->aspace = new_address_space ();
+ child_inf->sspace = add_symbol_space (child_inf->aspace);
+ child_inf->sspace->removable = 1;
+ set_current_symbol_space (child_inf->sspace);
+ clone_symbol_space (child_inf->sspace, parent_sspace);
+
+ /* Let the shared library layer (solib-svr4) learn about
+ this new process, relocate the cloned exec, pull in
+ shared libraries, and install the solib event breakpoint.
+ If a "cloned-VM" event was propagated better throughout
+ the core, this wouldn't be required. */
+ solib_create_inferior_hook ();
+ }
+ /* Let the thread_db layer learn about this new process. */
check_for_thread_db ();
}
@@ -1612,7 +1718,16 @@ linux_nat_detach (struct target_ops *ops
static int
resume_callback (struct lwp_info *lp, void *data)
{
- if (lp->stopped && lp->status == 0)
+ struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
+
+ if (lp->stopped && inf->vfork_child != NULL)
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "RC: Not resuming %s (vfork parent)\n",
+ target_pid_to_str (lp->ptid));
+ }
+ else if (lp->stopped && lp->status == 0)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -1733,7 +1848,7 @@ linux_nat_resume (struct target_ops *ops
}
}
- if (lp->status)
+ if (lp->status || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
{
/* FIXME: What should we do if we are supposed to continue
this thread with a signal? */
@@ -1961,25 +2076,28 @@ linux_handle_extended_wait (struct lwp_i
ourstatus->value.execd_pathname
= xstrdup (linux_child_pid_to_exec_file (pid));
- if (linux_parent_pid)
+ return 0;
+ }
+
+ if (event == PTRACE_EVENT_VFORK_DONE)
+ {
+ if (current_inferior ()->waiting_for_vfork_done)
{
- detach_breakpoints (linux_parent_pid);
- ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog, "\
+LHEW: Got expected PTRACE_EVENT_VFORK_DONE from LWP %ld: stopping\n",
+ GET_LWP (lp->ptid));
- linux_parent_pid = 0;
+ ourstatus->kind = TARGET_WAITKIND_VFORK_DONE;
+ return 0;
}
- /* At this point, all inserted breakpoints are gone. Doing this
- as soon as we detect an exec prevents the badness of deleting
- a breakpoint writing the current "shadow contents" to lift
- the bp. That shadow is NOT valid after an exec.
-
- Note that we have to do this after the detach_breakpoints
- call above, otherwise breakpoints wouldn't be lifted from the
- parent on a vfork, because detach_breakpoints would think
- that breakpoints are not inserted. */
- mark_breakpoints_out ();
- return 0;
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog, "\
+LHEW: Got PTRACE_EVENT_VFORK_DONE from LWP %ld: resuming\n",
+ GET_LWP (lp->ptid));
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ return 1;
}
internal_error (__FILE__, __LINE__,
@@ -2169,6 +2287,13 @@ maybe_clear_ignore_sigint (struct lwp_in
static int
stop_wait_callback (struct lwp_info *lp, void *data)
{
+ struct inferior *inf = find_inferior_pid (GET_PID (lp->ptid));
+
+ /* If this is a vfork parent, bail out, it is not going to report
+ any SIGSTOP until the vfork is done with. */
+ if (inf->vfork_child != NULL)
+ return 0;
+
if (!lp->stopped)
{
int status;
@@ -2392,7 +2517,7 @@ cancel_breakpoint (struct lwp_info *lp)
CORE_ADDR pc;
pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch);
- if (breakpoint_inserted_here_p (pc))
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
Index: src/gdb/linux-thread-db.c
===================================================================
--- src.orig/gdb/linux-thread-db.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/linux-thread-db.c 2009-09-03 03:02:39.000000000 +0100
@@ -1226,18 +1226,15 @@ thread_db_wait (struct target_ops *ops,
if (ourstatus->kind == TARGET_WAITKIND_EXECD)
{
- /* Breakpoints have already been marked non-inserted by the
- layer below. We're safe in knowing that removing them will
- not write the shadows of the old image into the new
- image. */
- remove_thread_event_breakpoints ();
-
/* New image, it may or may not end up using thread_db. Assume
not unless we find otherwise. */
delete_thread_db_info (GET_PID (ptid));
if (!thread_db_list)
unpush_target (&thread_db_ops);
+ /* Thread event breakpoints are deleted by
+ update_breakpoints_after_exec. */
+
return ptid;
}
@@ -1274,13 +1271,12 @@ thread_db_mourn_inferior (struct target_
delete_thread_db_info (GET_PID (inferior_ptid));
- /* Delete the old thread event breakpoints. Mark breakpoints out,
- so that we don't try to un-insert them. */
- mark_breakpoints_out ();
- remove_thread_event_breakpoints ();
-
target_beneath->to_mourn_inferior (target_beneath);
+ /* Delete the old thread event breakpoints. Do this after mourning
+ the inferior, so that we don't try to uninsert them. */
+ remove_thread_event_breakpoints ();
+
/* Detach thread_db target ops. */
if (!thread_db_list)
unpush_target (ops);
Index: src/gdb/corelow.c
===================================================================
--- src.orig/gdb/corelow.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/corelow.c 2009-09-03 03:02:39.000000000 +0100
@@ -45,6 +45,7 @@
#include "exceptions.h"
#include "solib.h"
#include "filenames.h"
+#include "symspace.h"
#ifndef O_LARGEFILE
@@ -286,6 +287,7 @@ core_open (char *filename, int from_tty)
int scratch_chan;
int flags;
int corelow_pid = CORELOW_PID;
+ struct inferior *inf;
target_preopen (from_tty);
if (!filename)
@@ -371,7 +373,9 @@ core_open (char *filename, int from_tty)
push_target (&core_ops);
discard_cleanups (old_chain);
- add_inferior_silent (corelow_pid);
+ inf = add_inferior_silent (corelow_pid);
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
/* Do this before acknowledging the inferior, so if
post_create_inferior throws (can happen easilly if you're loading
Index: src/gdb/remote.c
===================================================================
--- src.orig/gdb/remote.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/remote.c 2009-09-03 03:02:39.000000000 +0100
@@ -1185,6 +1185,23 @@ remote_add_inferior (int pid, int attach
inf->attach_flag = attached;
+ inf->sspace = current_symbol_space;
+
+ if (gdbarch_has_global_solist (target_gdbarch))
+ {
+ /* If the target shares code across all inferiors, then every
+ inferior will use the same symbol space. However, each
+ inferior may still have its own address space. */
+ inf->aspace = maybe_new_address_space ();
+ }
+ else
+ {
+ /* In the traditional debugging scenario, there's a 1-1 match
+ between symbol/address spaces. We simply bind the inferior
+ to the symbol space's address space. */
+ inf->aspace = inf->sspace->aspace;
+ }
+
return inf;
}
@@ -2637,6 +2654,10 @@ remote_start_remote (struct ui_out *uiou
this before anything involving memory or registers. */
target_find_description ();
+ /* Next, now that we know something about the target, update the
+ address spaces in the symbol spaces. */
+ update_address_spaces ();
+
/* On OSs where the list of libraries is global to all
processes, we fetch them early. */
if (gdbarch_has_global_solist (target_gdbarch))
@@ -6763,11 +6784,14 @@ extended_remote_create_inferior_1 (char
extended_remote_restart ();
}
- /* Clean up from the last time we ran, before we mark the target
- running again. This will mark breakpoints uninserted, and
- get_offsets may insert breakpoints. */
- init_thread_list ();
- init_wait_for_inferior ();
+ if (!have_inferiors ())
+ {
+ /* Clean up from the last time we ran, before we mark the target
+ running again. This will mark breakpoints uninserted, and
+ get_offsets may insert breakpoints. */
+ init_thread_list ();
+ init_wait_for_inferior ();
+ }
/* Now mark the inferior as running before we do anything else. */
inferior_ptid = magic_null_ptid;
Index: src/gdb/darwin-nat.c
===================================================================
--- src.orig/gdb/darwin-nat.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/darwin-nat.c 2009-09-03 03:02:39.000000000 +0100
@@ -1517,6 +1517,8 @@ darwin_attach (struct target_ops *ops, c
inferior_ptid = pid_to_ptid (pid);
inf = add_inferior (pid);
inf->attach_flag = 1;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
/* Always add a main thread. */
add_thread_silent (inferior_ptid);
Index: src/gdb/gnu-nat.c
===================================================================
--- src.orig/gdb/gnu-nat.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/gnu-nat.c 2009-09-03 03:02:39.000000000 +0100
@@ -2168,6 +2168,8 @@ gnu_attach (struct target_ops *ops, char
inferior = add_inferior (pid);
inferior->attach_flag = 1;
+ inferior->sspace = current_symbol_space;
+ inferior->aspace = inferior->sspace->aspace;
inf_update_procs (inf);
Index: src/gdb/go32-nat.c
===================================================================
--- src.orig/gdb/go32-nat.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/go32-nat.c 2009-09-03 03:02:39.000000000 +0100
@@ -649,6 +649,7 @@ go32_create_inferior (struct target_ops
char *cmdline;
char **env_save = environ;
size_t cmdlen;
+ struct inferior *inf;
/* If no exec file handed to us, get it from the exec-file command -- with
a good, common error message if none is specified. */
@@ -714,7 +715,9 @@ go32_create_inferior (struct target_ops
#endif
inferior_ptid = pid_to_ptid (SOME_PID);
- add_inferior_silent (SOME_PID);
+ inf = add_inferior_silent (SOME_PID);
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
push_target (&go32_ops);
Index: src/gdb/inf-ttrace.c
===================================================================
--- src.orig/gdb/inf-ttrace.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/inf-ttrace.c 2009-09-03 03:02:39.000000000 +0100
@@ -453,6 +453,8 @@ inf_ttrace_follow_fork (struct target_op
inferior_ptid = ptid_build (fpid, flwpid, 0);
inf = add_inferior (fpid);
inf->attach_flag = parent_inf->attach_flag;
+ inf->sspace = parent_inf->sspace;
+ inf->aspace = parent_inf->aspace;
copy_terminal_info (inf, parent_inf);
detach_breakpoints (pid);
@@ -727,6 +729,8 @@ inf_ttrace_attach (struct target_ops *op
inf = add_inferior (pid);
inf->attach_flag = 1;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
/* Set the initial event mask. */
memset (&tte, 0, sizeof (tte));
Index: src/gdb/monitor.c
===================================================================
--- src.orig/gdb/monitor.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/monitor.c 2009-09-03 03:02:39.000000000 +0100
@@ -705,6 +705,7 @@ monitor_open (char *args, struct monitor
{
char *name;
char **p;
+ struct inferior *inf;
if (mon_ops->magic != MONITOR_OPS_MAGIC)
error (_("Magic number of monitor_ops struct wrong."));
@@ -822,7 +823,9 @@ monitor_open (char *args, struct monitor
/* Make run command think we are busy... */
inferior_ptid = monitor_ptid;
- add_inferior_silent (ptid_get_pid (inferior_ptid));
+ inf = add_inferior_silent (ptid_get_pid (inferior_ptid));
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
add_thread_silent (inferior_ptid);
/* Give monitor_wait something to read */
Index: src/gdb/nto-procfs.c
===================================================================
--- src.orig/gdb/nto-procfs.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/nto-procfs.c 2009-09-03 03:02:39.000000000 +0100
@@ -642,6 +642,8 @@ procfs_attach (struct target_ops *ops, c
inferior_ptid = do_attach (pid_to_ptid (pid));
inf = add_inferior (pid);
inf->attach_flag = 1;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
push_target (ops);
@@ -1198,6 +1200,8 @@ procfs_create_inferior (struct target_op
inf = add_inferior (pid);
inf->attach_flag = 0;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */
errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0);
Index: src/gdb/procfs.c
===================================================================
--- src.orig/gdb/procfs.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/procfs.c 2009-09-03 03:02:39.000000000 +0100
@@ -3708,6 +3708,8 @@ do_attach (ptid_t ptid)
inf = add_inferior (pi->pid);
/* Let GDB know that the inferior was attached. */
inf->attach_flag = 1;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
/* Create a procinfo for the current lwp. */
lwpid = proc_get_current_thread (pi);
Index: src/gdb/windows-nat.c
===================================================================
--- src.orig/gdb/windows-nat.c 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/windows-nat.c 2009-09-03 03:02:39.000000000 +0100
@@ -1587,6 +1587,8 @@ do_initial_windows_stuff (struct target_
inf = add_inferior (pid);
inf->attach_flag = attaching;
+ inf->sspace = current_symbol_space;
+ inf->aspace = inf->sspace->aspace;
/* Make the new process the current inferior, so terminal handling
can rely on it. When attaching, we don't know about any thread
Index: src/gdb/tui/tui-disasm.c
===================================================================
--- src.orig/gdb/tui/tui-disasm.c 2009-09-03 03:00:14.000000000 +0100
+++ src/gdb/tui/tui-disasm.c 2009-09-03 03:02:39.000000000 +0100
@@ -36,6 +36,7 @@
#include "tui/tui-stack.h"
#include "tui/tui-file.h"
#include "tui/tui-disasm.h"
+#include "symspace.h"
#include "gdb_curses.h"
@@ -259,7 +260,8 @@ tui_set_disassem_content (struct gdbarch
/* See whether there is a breakpoint installed. */
src->has_break = (!src->is_exec_point
- && breakpoint_here_p (pc) != no_breakpoint_here);
+ && breakpoint_here_p (current_symbol_space->aspace, pc)
+ != no_breakpoint_here);
xfree (asm_lines[i].addr_string);
xfree (asm_lines[i].insn);
Index: src/gdb/testsuite/gdb.base/foll-vfork.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-vfork.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-vfork.exp 2009-09-03 03:02:39.000000000 +0100
@@ -93,10 +93,10 @@ proc check_vfork_catchpoints {} {
proc vfork_parent_follow_through_step {} {
global gdb_prompt
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, vfork through step"}
- timeout {fail "set follow parent, vfork through step"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, vfork through step"}
+ timeout {fail "set follow-fork parent, vfork through step"}
}
send_gdb "next\n"
gdb_expect {
@@ -116,10 +116,10 @@ proc vfork_parent_follow_to_bp {} {
global gdb_prompt
global srcfile
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, vfork to bp"}
- timeout {fail "set follow parent, vfork to bp"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, vfork to bp"}
+ timeout {fail "set follow-fork parent, vfork to bp"}
}
send_gdb "break ${srcfile}:18\n"
gdb_expect {
@@ -144,14 +144,14 @@ proc vfork_and_exec_child_follow_to_main
global gdb_prompt
global binfile
- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, vfork and exec to main bp"}
- timeout {fail "set follow child, vfork and exec to main bp"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec to main bp"}
+ timeout {fail "set follow-fork child, vfork and exec to main bp"}
}
send_gdb "continue\n"
gdb_expect {
- -re "Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
+ -re "Attaching after.* vfork to.*xecuting new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
{pass "vfork and exec child follow, to main bp"}
-re "$gdb_prompt $" {fail "vfork and exec child follow, to main bp"}
timeout {fail "(timeout) vfork and exec child follow, to main bp" }
@@ -193,7 +193,7 @@ proc vfork_and_exec_child_follow_through
# This test cannot be performed prior to HP-UX 10.30, because ptrace-based
# debugging of a vforking program basically doesn't allow the child to do
# things like hit a breakpoint between a vfork and exec. This means that
-# saying "set follow child; next" at a vfork() call won't work, because
+# saying "set follow-fork child; next" at a vfork() call won't work, because
# the implementation of "next" sets a "step resume" breakpoint at the
# return from the vfork(), which the child will hit on its way to exec'ing.
#
@@ -202,10 +202,10 @@ proc vfork_and_exec_child_follow_through
return 0
}
- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, vfork and exec through step"}
- timeout {fail "set follow child, vfork and exec through step"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, vfork and exec through step"}
+ timeout {fail "set follow-fork child, vfork and exec through step"}
}
send_gdb "next\n"
gdb_expect {
@@ -248,10 +248,10 @@ proc tcatch_vfork_then_parent_follow {}
global gdb_prompt
global srcfile
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent, tcatch vfork"}
- timeout {fail "set follow parent, tcatch vfork"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent, tcatch vfork"}
+ timeout {fail "set follow-fork parent, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {
@@ -294,10 +294,10 @@ proc tcatch_vfork_then_child_follow {} {
global srcfile
global srcfile2
- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child, tcatch vfork"}
- timeout {fail "set follow child, tcatch vfork"}
+ -re "$gdb_prompt $" {pass "set follow-fork child, tcatch vfork"}
+ timeout {fail "set follow-fork child, tcatch vfork"}
}
send_gdb "tcatch vfork\n"
gdb_expect {
Index: src/gdb/testsuite/gdb.base/foll-exec.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-exec.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-exec.exp 2009-09-03 03:02:39.000000000 +0100
@@ -152,7 +152,7 @@ proc do_exec_tests {} {
#
send_gdb "next\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execlp call"}
-re "$gdb_prompt $" {fail "step through execlp call"}
timeout {fail "(timeout) step through execlp call"}
@@ -230,7 +230,7 @@ proc do_exec_tests {} {
setup_xfail hppa2.0w-hp-hpux* CLLbs16760
send_gdb "continue\n"
gdb_expect {
- -re ".*Executing new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
+ -re ".*xecuting new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
{pass "hit catch exec"}
-re "$gdb_prompt $" {fail "hit catch exec"}
timeout {fail "(timeout) hit catch exec"}
@@ -299,7 +299,7 @@ proc do_exec_tests {} {
#
send_gdb "next 2\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execl call"}
-re "$gdb_prompt $" {fail "step through execl call"}
timeout {fail "(timeout) step through execl call"}
@@ -353,7 +353,7 @@ proc do_exec_tests {} {
}
send_gdb "next\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "step through execv call"}
-re "$gdb_prompt $" {fail "step through execv call"}
timeout {fail "(timeout) step through execv call"}
@@ -394,7 +394,7 @@ proc do_exec_tests {} {
#
send_gdb "continue\n"
gdb_expect {
- -re "Executing new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
+ -re ".*xecuting new program: .*${testfile2}.*${srcfile2}:23.*int local_j = argc;.*$gdb_prompt $"\
{pass "continue through exec"}
-re "$gdb_prompt $" {fail "continue through exec"}
timeout {fail "(timeout) continue through exec"}
Index: src/gdb/testsuite/gdb.base/foll-fork.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/foll-fork.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/foll-fork.exp 2009-09-03 03:02:39.000000000 +0100
@@ -64,7 +64,7 @@ proc check_fork_catchpoints {} {
proc default_fork_parent_follow {} {
global gdb_prompt
- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "default show parent follow, no catchpoints"}
@@ -88,12 +88,12 @@ proc default_fork_parent_follow {} {
proc explicit_fork_parent_follow {} {
global gdb_prompt
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent"}
+ timeout {fail "(timeout) set follow-fork parent"}
}
- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
{pass "explicit show parent follow, no catchpoints"}
@@ -117,12 +117,12 @@ proc explicit_fork_parent_follow {} {
proc explicit_fork_child_follow {} {
global gdb_prompt
- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
+ -re "$gdb_prompt $" {pass "set follow-fork child"}
+ timeout {fail "(timeout) set follow-fork child"}
}
- send_gdb "show follow\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\"..*$gdb_prompt $"\
{pass "explicit show child follow, no catchpoints"}
@@ -131,7 +131,7 @@ proc explicit_fork_child_follow {} {
}
send_gdb "next 2\n"
gdb_expect {
- -re "Attaching after fork to.*$gdb_prompt $"\
+ -re "Attaching after.* fork to.*$gdb_prompt $"\
{pass "explicit child follow, no catchpoints"}
-re "$gdb_prompt $" {fail "explicit child follow, no catchpoints"}
timeout {fail "(timeout) explicit child follow, no catchpoints"}
@@ -185,24 +185,24 @@ proc catch_fork_child_follow {} {
}
}
- send_gdb "set follow child\n"
+ send_gdb "set follow-fork child\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
+ -re "$gdb_prompt $" {pass "set follow-fork child"}
+ timeout {fail "(timeout) set follow-fork child"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
- {pass "set follow child, tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
+ {pass "set follow-fork child, tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, tbreak"}
+ timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
- -re "Attaching after fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
- {pass "set follow child, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
- timeout {fail "(timeout) set follow child, hit tbreak"}
+ -re "Attaching after.* fork to.* at .*$bp_after_fork.*$gdb_prompt $"\
+ {pass "set follow-fork child, hit tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, hit tbreak"}
+ timeout {fail "(timeout) set follow-fork child, hit tbreak"}
}
# The parent has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@@ -215,12 +215,12 @@ proc catch_fork_child_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
- {pass "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
+ {pass "set follow-fork child, cleanup"}
+ timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}
- -re "$gdb_prompt $" {fail "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
+ -re "$gdb_prompt $" {fail "set follow-fork child, cleanup"}
+ timeout {fail "(timeout) set follow-fork child, cleanup"}
}
}
@@ -244,7 +244,7 @@ proc catch_fork_unpatch_child {} {
"Breakpoint .*file .*$srcfile, line .*" \
"unpatch child, breakpoint at exit call"
- gdb_test "set follow child" "" "unpatch child, set follow child"
+ gdb_test "set follow-fork child" "" "unpatch child, set follow-fork child"
set test "unpatch child, unpatched parent breakpoints from child"
gdb_test_multiple "continue" $test {
@@ -297,24 +297,24 @@ proc tcatch_fork_parent_follow {} {
-re "$gdb_prompt $" {fail "explicit parent follow, tcatch fork"}
timeout {fail "(timeout) explicit parent follow, tcatch fork"}
}
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
+ -re "$gdb_prompt $" {pass "set follow-fork parent"}
+ timeout {fail "(timeout) set follow-fork parent"}
}
send_gdb "tbreak ${srcfile}:$bp_after_fork\n"
gdb_expect {
-re "Temporary breakpoint.*, line $bp_after_fork.*$gdb_prompt $"\
- {pass "set follow parent, tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
+ {pass "set follow-fork parent, tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, tbreak"}
+ timeout {fail "(timeout) set follow-fork child, tbreak"}
}
send_gdb "continue\n"
gdb_expect {
-re ".*Detaching after fork from.* at .*$bp_after_fork.*$gdb_prompt $"\
- {pass "set follow parent, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, hit tbreak"}
- timeout {fail "(timeout) set follow parent, hit tbreak"}
+ {pass "set follow-fork parent, hit tbreak"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, hit tbreak"}
+ timeout {fail "(timeout) set follow-fork parent, hit tbreak"}
}
# The child has been detached; allow time for any output it might
# generate to arrive, so that output doesn't get confused with
@@ -327,12 +327,12 @@ proc tcatch_fork_parent_follow {} {
send_gdb "y\n"
gdb_expect {
-re "$gdb_prompt $"\
- {pass "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
+ {pass "set follow-fork parent, cleanup"}
+ timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}
- -re "$gdb_prompt $" {fail "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
+ -re "$gdb_prompt $" {fail "set follow-fork parent, cleanup"}
+ timeout {fail "(timeout) set follow-fork parent, cleanup"}
}
}
@@ -349,35 +349,35 @@ A fork or vfork creates a new process.
.*child - the new process is debugged after a fork.*
The unfollowed process will continue to run..*
By default, the debugger will follow the parent process..*$gdb_prompt $"\
- { pass "help set follow" }
+ { pass "help set follow-fork" }
-re "$gdb_prompt $" { fail "help set follow" }
- timeout { fail "(timeout) help set follow" }
+ timeout { fail "(timeout) help set follow-fork" }
}
# Verify that we can set follow-fork-mode, using an abbreviation
# for both the flag and its value.
#
- send_gdb "set follow ch\n"
- send_gdb "show fol\n"
+ send_gdb "set follow-fork ch\n"
+ send_gdb "show follow-fork\n"
gdb_expect {
-re "Debugger response to a program call of fork or vfork is \"child\".*$gdb_prompt $"\
- {pass "set follow, using abbreviations"}
- timeout {fail "(timeout) set follow, using abbreviations"}
+ {pass "set follow-fork, using abbreviations"}
+ timeout {fail "(timeout) set follow-fork, using abbreviations"}
}
# Verify that we cannot set follow-fork-mode to nonsense.
#
- send_gdb "set follow chork\n"
+ send_gdb "set follow-fork chork\n"
gdb_expect {
-re "Undefined item: \"chork\".*$gdb_prompt $"\
- {pass "set follow to nonsense is prohibited"}
- -re "$gdb_prompt $" {fail "set follow to nonsense is prohibited"}
- timeout {fail "(timeout) set follow to nonsense is prohibited"}
+ {pass "set follow-fork to nonsense is prohibited"}
+ -re "$gdb_prompt $" {fail "set follow-fork to nonsense is prohibited"}
+ timeout {fail "(timeout) set follow-fork to nonsense is prohibited"}
}
- send_gdb "set follow parent\n"
+ send_gdb "set follow-fork parent\n"
gdb_expect {
- -re "$gdb_prompt $" {pass "set follow to nonsense is prohibited (reset parent)"}
- timeout {fail "set follow to nonsense is prohibited (reset parent)"}
+ -re "$gdb_prompt $" {pass "set follow-fork to nonsense is prohibited (reset parent)"}
+ timeout {fail "set follow-fork to nonsense is prohibited (reset parent)"}
}
# Check that fork catchpoints are supported, as an indicator for whether
Index: src/gdb/testsuite/gdb.base/multi-forks.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/multi-forks.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/multi-forks.exp 2009-09-03 03:02:39.000000000 +0100
@@ -121,7 +121,7 @@ proc continue_to_exit_bp_loc {} {
# The result should be that each of the 4 forks returns zero.
runto_main
-gdb_test "set follow child"
+gdb_test "set follow-fork child"
continue_to_exit_bp_loc
gdb_test "print pids" "\\$.* = \\{0, 0, 0, 0\\}.*" "follow child, print pids"
@@ -130,7 +130,7 @@ gdb_test "print pids" "\\$.* = \\{0, 0,
# Result should be that none of the 4 forks returns zero.
runto_main
-gdb_test "set follow parent" "" ""
+gdb_test "set follow-fork parent" "" ""
continue_to_exit_bp_loc
gdb_test "print pids\[0\]==0 || pids\[1\]==0 || pids\[2\]==0 || pids\[3\]==0" \
Index: src/gdb/testsuite/gdb.base/attach.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/attach.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/attach.exp 2009-09-03 03:02:39.000000000 +0100
@@ -291,7 +291,7 @@ proc do_attach_tests {} {
# Explicitly flush out any knowledge of the previous attachment.
set test "before attach3, flush symbols"
- gdb_test_multiple "symbol" "$test" {
+ gdb_test_multiple "symbol-file" "$test" {
-re "Discard symbol table from.*y or n. $" {
gdb_test "y" "No symbol file now." \
"$test"
Index: src/gdb/testsuite/gdb.base/maint.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/maint.exp 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/maint.exp 2009-09-03 03:02:39.000000000 +0100
@@ -480,9 +480,9 @@ set bp_location6 [gdb_get_line_number "s
send_gdb "maint info breakpoints\n"
gdb_expect {
- -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
+ -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex\[ \t\]+in main at.*break.c:$bp_location6 sspace 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n.*$gdb_prompt $"\
{ pass "maint info breakpoints" }
- -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
+ -re "Num\[ \t\]+Type\[ \t\]+Disp\[ \t\]+Enb\[ \t\]+Address\[ \t\]+What\r\n1\[ \t\]+breakpoint\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex in main at.*break.c:$bp_location6 sspace 1\r\n\[ \t\]+breakpoint already hit 1 time\r\n-1\[ \t\]+shlib events\[ \t\]+keep\[ \t\]+y\[ \t\]+$hex.*breakpoint already hit.*$gdb_prompt $"\
{ pass "maint info breakpoints (with shlib events)" }
-re ".*$gdb_prompt $" { fail "maint info breakpoints" }
timeout { fail "(timeout) maint info breakpoints" }
Index: src/gdb/testsuite/Makefile.in
===================================================================
--- src.orig/gdb/testsuite/Makefile.in 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/testsuite/Makefile.in 2009-09-03 03:02:39.000000000 +0100
@@ -35,7 +35,7 @@ SUBDIRS = @subdirs@
RPATH_ENVVAR = @RPATH_ENVVAR@
ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm gdb.base gdb.cp gdb.disasm \
gdb.dwarf2 \
- gdb.fortran gdb.server gdb.java gdb.mi \
+ gdb.fortran gdb.server gdb.java gdb.mi gdb.multi \
gdb.objc gdb.opt gdb.pascal gdb.python gdb.threads gdb.trace \
gdb.xml \
$(SUBDIRS)
Index: src/gdb/testsuite/gdb.multi/Makefile.in
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/Makefile.in 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,14 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = hello hangout goodbye bkpt-multi-exec crashme
+
+all info install-info dvi install uninstall installcheck check:
+ @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+ -rm -f *~ *.o *.ci
+ -rm -f core $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+ -rm -f Makefile config.status config.log
Index: src/gdb/testsuite/gdb.multi/base.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/base.exp 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,102 @@
+# Copyright 2009 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Test multi-exec / multi-process features that work for all configurations,
+# even ones that cannot run multiple processes simultaneously.
+
+set testfile "base"
+
+set exec1 "hello"
+set srcfile1 ${exec1}.c
+set binfile1 ${objdir}/${subdir}/${exec1}
+
+set exec2 "hangout"
+set srcfile2 ${exec2}.c
+set binfile2 ${objdir}/${subdir}/${exec2}
+
+set exec3 "goodbye"
+set srcfile3 ${exec3}.c
+set binfile3 ${objdir}/${subdir}/${exec3}
+
+if { [prepare_for_testing ${testfile}.exp ${exec1} "${srcfile1}" {debug nowarnings}] } {
+ return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${exec2} "${srcfile2}" {debug nowarnings}] } {
+ return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${exec3} "${srcfile3}" {debug nowarnings}] } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile1}
+
+# Add an empty symbol space, switch to it, and load a main executable
+# into it.
+gdb_test "add-symbol-space" "1 symbol spaces added.*"
+gdb_test "sspace 2" "Switching to sspace 2.*"
+gdb_test "file ${binfile2}" ""
+
+# Add a new symbol space and load a main executable into it in one
+# command.
+gdb_test "add-symbol-space -exec ${binfile3}"
+
+# Check that we have multiple spaces.
+
+gdb_test "info sspaces" \
+ "Main Program.*${exec3}.*${exec2}.*${exec1}.*"
+
+# Test that we have multiple symbol tables.
+
+gdb_test "sspace 1"
+gdb_test "info functions commonfun" "${srcfile1}.*"
+
+gdb_test "sspace 3"
+gdb_test "info functions commonfun" "${srcfile3}.*"
+
+
+gdb_test "sspace 1"
+
+gdb_test "set listsize 1" ""
+
+gdb_test "list commonfun" "from hello.*"
+
+gdb_test "print hglob" "1"
+
+gdb_test "print glob" "92" "print glob (${exec1})"
+
+
+gdb_test "sspace 3"
+
+gdb_test "print gglob" "2"
+
+gdb_test "print glob" "45" "print glob (${exec3})"
+
+gdb_test "list commonfun" "from goodbye.*"
+
+
+# Let's run the hello program.
+gdb_test "sspace 1"
+
+if { ![runto_main] } then {
+ return -1
+}
+
+gdb_test "break hello" ""
+gdb_test "continue" "Breakpoint \[0-9\].*, hello.*"
Index: src/gdb/testsuite/gdb.multi/goodbye.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/goodbye.c 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,62 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ 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/>. */
+
+int gglob = 2;
+
+int glob = 45;
+
+int verylongfun()
+{
+ glob += 2;
+ glob *= 2;
+ glob += 3;
+ glob *= 3;
+ glob += 4;
+ glob *= 4;
+ glob += 5;
+ glob *= 5;
+ glob += 6;
+ glob *= 6;
+ glob += 7;
+ glob *= 7;
+ glob += 8;
+ glob *= 8;
+ glob += 9;
+ glob *= 9;
+}
+
+main() {
+ mailand();
+ foo(glob);
+ verylongfun();
+ goodbye();
+}
+
+foo(int x) {
+ return x + 92;
+}
+
+mailand()
+{
+ glob = 46;
+}
+
+void commonfun() { mailand(); } /* from goodbye */
+
+goodbye() {
+ ++glob;
+}
Index: src/gdb/testsuite/gdb.multi/hangout.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/hangout.c 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ 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/>. */
+
+main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < argc; ++i)
+ {
+ printf("Arg %d is %s\n", i, argv[i]);
+ }
+}
Index: src/gdb/testsuite/gdb.multi/hello.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/hello.c 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,46 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ 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/>. */
+
+short hglob = 1;
+
+short glob = 92;
+
+int commonfun() { bar(); } /* from hello */
+
+bar()
+{
+ if (glob == 0)
+ exit(1);
+}
+
+hello(int x)
+{
+ x *= 2;
+ return x + 45;
+}
+
+main()
+{
+ int tmpx;
+
+ bar();
+ tmpx = hello(glob);
+ commonfun();
+ glob = tmpx;
+ commonfun();
+}
+
Index: src/gdb/testsuite/gdb.multi/bkpt-multi-exec.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/bkpt-multi-exec.c 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+int main (void)
+{
+ printf ("foll-exec is about to execl(crashme)...\n");
+
+ execl ("gdb.multi/crashme",
+ "gdb.multi/crashme",
+ (char *)0);
+}
Index: src/gdb/testsuite/gdb.multi/bkpt-multi-exec.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/bkpt-multi-exec.exp 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,84 @@
+# Copyright 2009 Free Software Foundation, Inc.
+
+# 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/>.
+
+if { [is_remote target] || ![isnative] } then {
+ continue
+}
+
+set testfile "bkpt-multi-exec"
+
+set exec1 "bkpt-multi-exec"
+set srcfile1 ${exec1}.c
+set binfile1 ${objdir}/${subdir}/${exec1}
+
+set exec2 "crashme"
+set srcfile2 ${exec2}.c
+set binfile2 ${objdir}/${subdir}/${exec2}
+
+if { [prepare_for_testing ${testfile}.exp ${exec1} "${srcfile1}" {debug nowarnings}] } {
+ return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${exec2} "${srcfile2}" {debug nowarnings}] } {
+ return -1
+}
+# Until "catch exec" is implemented on other targets...
+#
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
+ continue
+}
+
+# Start with a fresh gdb
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile1}
+
+# Start the program running, and stop at main.
+#
+if ![runto_main] then {
+ perror "Couldn't run ${binfile1}"
+ return
+}
+
+delete_breakpoints
+
+# continuing should exec and trigger the bug
+gdb_test "continue" "SIGSEGV.*"
+
+# Start over, but this time, set a breakpoint before the app crashes.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile1}
+
+gdb_test "add-symbol-space -exec ${binfile2}"
+
+set bp_location [gdb_get_line_number "set breakpoint here" ${srcfile2}]
+
+gdb_test "sspace 2"
+gdb_test "break ${srcfile2}:${bp_location}" ""
+
+# Start the program running, and stop at main.
+#
+gdb_test "sspace 1"
+
+# Now run to the breakpoint. This should cross the exec, and stop at
+# the breakpoint before the crash.
+gdb_test "run" "${srcfile2}:${bp_location}.*set breakpoint here.*"
+
+return 0
Index: src/gdb/testsuite/gdb.multi/crashme.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/testsuite/gdb.multi/crashme.c 2009-09-03 03:02:39.000000000 +0100
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ int *foo = NULL;
+
+ printf ("Oh no, a bug!\n"); /* set breakpoint here */
+
+ return *foo;
+}
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/doc/gdb.texinfo 2009-09-03 03:02:39.000000000 +0100
@@ -1792,8 +1792,9 @@ kill a child process.
* Kill Process:: Killing the child process
* Inferiors:: Debugging multiple inferiors
+* Multiple Programs:: Debugging multiple programs
* Threads:: Debugging programs with multiple threads
-* Processes:: Debugging programs with multiple processes
+* Forks:: Debugging forks
* Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@end menu
@@ -2384,6 +2385,16 @@ the inferior number assigned by @value{G
@item
the target system's inferior identifier
+
+@item
+the symbol space ID the inferior is bound to. @xref{Multiple
+Programs, ,Debugging Multiple Programs}.
+
+@item
+the name of the executable the inferior is running. As a convenience,
+this is the same information @code{info sspaces} outputs in its
+@code{Main Program} column.
+
@end enumerate
@noindent
@@ -2396,11 +2407,16 @@ For example,
@smallexample
(@value{GDBP}) info inferiors
- Num Description
-* 1 process 2307
- 2 process 3401
+ Num Description SSpace Main Program
+ 2 process 2307 2 helloworld
+* 1 process 3401 1 helloworld
@end smallexample
+In addition, below each inferior line, @value{GDBN} prints extra
+information that isn't suitable to display in tabular form. For
+example, extra vfork parent/child relationships.
+@xref{Forks,,Debugging forks}.
+
To switch focus between inferiors, use the @code{inferior} command:
@table @code
@@ -2447,6 +2463,144 @@ Show whether messages will be printed wh
inferiors have started, exited or have been detached.
@end table
+@node Multiple Programs
+@section Debugging Multiple Programs
+
+@value{GDBN} lets you run and debug multiple programs in a single
+session. In addition, @value{GDBN} on some systems may let you run
+several programs simultaneously (otherwise you have to exit from one
+before starting another). In the most general case, you can have
+multiple threads of execution in each of multiple processes, launched
+from multiple executables.
+
+@cindex inferior
+@value{GDBN} represents the state of each program execution with an
+object called an @dfn{inferior}. An inferior typically corresponds to
+a process, but is more general and applies also to targets that don't
+have processes. Each run of an executable creates a new inferior, as
+does each attachment to an existing process. Inferiors have unique
+identifiers that are different from process ids. Usually each
+inferior will also have its own distinct address space, although in
+some cases, you'll have more than one inferior running in the same
+address space, like when debugging programs that call @code{vfork}.
+Other examples include embedded targets that may have several
+inferiors running in different parts of a single address space. Each
+inferior may in turn have multiple threads running in it.
+
+@cindex symbol space
+To keep everything straight, @value{GDBN} represents a symbolic view
+of an address space with an object called a @dfn{symbol space}. In
+the tradicional debugging scenario, there's a one-to-one
+correspondance between a symbol space, an inferior and an address
+space. On embedded targets that may have several inferiors running in
+different parts of a single address space, each inferior is still
+bound to its own symbol space --- meaning that @value{GDBN} manages
+the single address space behind the scenes. On some other targets,
+even though each inferior runs in its own address space, they all run
+the same code and see all symbols at the same addresses. In such
+cases, all inferiors are bound to the same symbol space.
+
+You can get multiple executables into a debugging session via the
+@code{add-symbol-space} command. On some systems @value{GDBN} can add
+programs to the debug session automatically by following calls to
+@code{fork} and @code{exec}.
+
+@table @code
+@kindex add-symbol-space
+@item add-symbol-space [ -copies @var{n} ] [ -exec @var{executable} ]
+Adds @var{n} symbol spaces to be run using @var{exec} as the
+executable. @var{n} defaults to 1. If no executable is specified,
+the symbol space begins empty. You can still load a program to the
+symbol space by using e.g., the @code{file} command with the
+executable name as its argument.
+
+@kindex remove-symbol-space
+@item remove-symbol-space @var{ID}
+Removes the symbol space @var{ID}.
+
+@kindex clone-symbol-space
+@item clone-symbol-space [ -copies @var{n} ] [ @var{ID} ]
+Adds @var{n} symbol spaces to be run using the same executable as
+symbol space @var{ID}. @var{n} defaults to 1.
+
+@kindex info symbol-spaces
+@kindex info sspaces
+@item info symbol-spaces
+Print a list of all symbol spaces currently being managed by
+@value{GDBN}.
+
+@value{GDBN} displays for each symbol space (in this order):
+
+@enumerate
+@item
+the symbol space number assigned by @value{GDBN}
+
+@item
+the name of the executable loaded into the symbol space, with e.g.,
+the @code{file} command.
+
+@end enumerate
+
+@noindent
+An asterisk @samp{*} preceding the @value{GDBN} symbol space number
+indicates the current symbol space.
+
+In addition, below each symbol space line, @value{GDBN} prints extra
+information that isn't suitable to display in tabular form. For
+example, the list of inferiors bound to the symbol space.
+
+For example,
+
+@smallexample
+(@value{GDBP}) info sspaces
+ Id Main Program
+ 2 goodbye
+ Bound inferiors: ID 1 (process 21561)
+* 1 hello
+@end smallexample
+
+Here we can see that no inferior is running the program @code{hello},
+while @code{process 21561} is running the program @code{goodbye}. On
+some targets, it is possible that multiple inferiors are bound to the
+same symbol space. The most common example is that of debugging both
+the parent and child processes of a @code{vfork}
+call. @xref{Forks,,Debugging Forks}.
+
+To switch focus between symbol spaces, use the @code{symbol-space}
+command:
+
+@kindex symbol-space
+@item symbol-space @var{ID}
+@itemx sspace @var{ID}
+Set symbol space @var{ID} as the current symbol space. If there's any
+inferior bound the the symbol space, @value{GDBN} switches focus to a
+thread of this inferior, otherwise, after the command, you have no
+thread selected.
+
+@smallexample
+(@value{GDBP}) info sspaces
+ Id Main Program
+ 2 hello
+* 1 goodbye
+ Bound inferiors: ID 1 (process 10685)
+(@value{GDBP}) sspace 2
+[Switching to sspace 2 (hello)]
+(@value{GDBP}) thread
+No thread selected
+(@value{GDBP}) sspace 1
+[Switching to thread 1]
+#0 main () at main.c:28
+28 printf ("goodbye\n");
+(@value{GDBP}) thread
+[Current thread is 1]
+@end smallexample
+
+@end table
+
+Many commands will work the same with multiple programs as with a
+single program: @code{print myglobal} will simply display the value of
+@code{myglobal} in the current symbol space.
+
@node Threads
@section Debugging Programs with Multiple Threads
@@ -2726,8 +2880,8 @@ only on some platforms.
Display current libthread_db search path.
@end table
-@node Processes
-@section Debugging Programs with Multiple Processes
+@node Forks
+@section Debugging Forks
@cindex fork, debugging programs which call
@cindex multiple processes
@@ -2807,6 +2961,19 @@ One process (child or parent, depending
@code{follow-fork-mode}) is debugged as usual, while the other
is held suspended.
+@smallexample
+(@value{GDBP}) info inferiors
+ Num Description SSpace Main Program
+* 2 process 21634 1 vfork-test
+ is vfork child of inferior 1
+ 1 process 21612 1 vfork-test
+ is vfork parent of inferior 2
+@end smallexample
+
+Note that in a vfork relationship, both parent and child share the
+same symbol space. @xref{Multiple Programs,,Debugging Multiple
+Programs}.
+
@end table
@kindex show detach-on-fork
@@ -2836,13 +3003,83 @@ On some systems, when a child process is
cannot debug the child or parent until an @code{exec} call completes.
If you issue a @code{run} command to @value{GDBN} after an @code{exec}
-call executes, the new target restarts. To restart the parent process,
-use the @code{file} command with the parent executable name as its
-argument.
+call executes, the new target restarts. To restart the parent
+process, use the @code{file} command with the parent executable name
+as its argument. By default, after an @code{exec} call executes,
+@value{GDBN} discards the symbols of the previous executable image.
+You can change this behaviour with the @w{@code{set follow-exec-mode}}
+command.
+
+@table @code
+@kindex set follow-exec-mode
+@item set follow-exec-mode @var{mode}
+
+Set debugger response to a program call of @code{exec}. An
+@code{exec} call replaces the process'es program image.
+@code{follow-exec-mode} can be:
+
+@table @code
+@item replace
+@value{GDBN} reuses the process'es symbol space, and replaces its
+loaded executable with the new executable the @code{exec} call loaded.
+This is the default.
+
+@smallexample
+(@value{GDBP}) info sspaces
+ Id Main Program
+* 1 prog1
+(@value{GDBP}) run
+process 12020 is executing new program: prog2
+Program exited normally.
+(@value{GDBP}) info sspaces
+ Id Main Program
+* 1 prog2
+@end smallexample
+
+@item keep
+@value{GDBN} keeps the current symbol space is kept unaltered so that
+it can be restarted afterwards, and @value{GDBN} assigns a new symbol
+space to the process, and loads it with the symbols of the executable
+the @code{exec} call loaded.
+
+@smallexample
+(@value{GDBP}) info sspaces
+(gdb) info sspaces
+ Id Main Program
+* 1 prog1
+(@value{GDBP}) run
+process 12020 is executing new program: prog2
+Program exited normally.
+(@value{GDBP}) info sspaces
+ Id Main Program
+* 1 prog1
+@end smallexample
+
+@end table
+@end table
You can use the @code{catch} command to make @value{GDBN} stop whenever
a @code{fork}, @code{vfork}, or @code{exec} call is made. @xref{Set
-Catchpoints, ,Setting Catchpoints}.
+Catchpoints, ,Setting Catchpoints}. Here's an example showing the
+interaction of @w{@code{catch exec}} and @w{@code{set follow-exec-mode
+keep}}:
+
+@smallexample
+(@value{GDBP}) info sspaces
+(gdb) info sspaces
+ Id Main Program
+* 1 prog1
+(@value{GDBP}) catch exec
+(@value{GDBP}) run
+process 12020 is executing new program: prog2
+Catchpoint 1 (exec'd prog2), 0x00007ffff7de0a60 in ?? ()
+ from /lib64/ld-linux-x86-64.so.2
+(@value{GDBP}) info sspaces
+ Id Main Program
+* 2 prog2
+ Bound inferiors: ID 2 (process 13791)
+ 1 prog1
+@end smallexample
@node Checkpoint/Restart
@section Setting a @emph{Bookmark} to Return to Later
@@ -13179,6 +13416,16 @@ via @code{gdbserver} (@pxref{Server, fil
Program}). In these situations the @value{GDBN} commands to specify
new files are useful.
+@value{GDBN} is capable of working with multiple programs at once, so
+you have the option of adding executables instead of replacing them,
+using commands such as @code{add-symbol-space} and @code{file}. While
+this can be useful, for instance to debug both client and server
+programs from the same @value{GDBN}, it can also be confusing to have
+several functions named @code{main}, several globals with the same
+name but different values, and so forth. You may wish to try using a
+separate @value{GDBN} instance for each program before deciding which
+is the better approach.
+
@table @code
@cindex executable file
@kindex file
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS 2009-09-03 03:00:13.000000000 +0100
+++ src/gdb/NEWS 2009-09-03 03:02:39.000000000 +0100
@@ -198,15 +198,16 @@ GDB will now correctly handle all of:
* Support for user-defined prefixed commands. The "define" command can
add new commands to existing prefixes, e.g. "target".
-* Multi-inferior, multi-process debugging.
+* Multi-inferior, multi-process, multi-program debugging.
- GDB now has generalized support for multi-inferior debugging. See
- "Debugging Multiple Inferiors" in the manual for more information.
- Although availability still depends on target support, the command
- set is more uniform now. The GNU/Linux specific multi-forks support
- has been migrated to this new framework. This implied some user
- visible changes; see "New commands" and also "Removed commands"
- below.
+ GDB now has generalized support for multi-inferior and multi-program
+ (a.k.a multi-exec) debugging. See "Debugging Multiple Inferiors"
+ and "Debugging Multiple Programs" in the manual for more
+ information. Although availability still depends on target support,
+ the command set is more uniform now. The GNU/Linux specific
+ multi-forks support has been migrated to the new multi-inferior
+ framework. This implied some user visible changes; see "New
+ commands" and also "Removed commands" below.
* Target descriptions can now describe the target OS ABI. See the
"Target Description Format" section in the user manual for more
@@ -266,6 +267,23 @@ detach inferior NUM
kill inferior NUM
Kill inferior number NUM.
+info symbol-spaces
+info sspaces
+ List the symbol spaces loaded into GDB.
+
+symbol-space NUM
+sspace NUM
+ Switch focus to symbol space number NUM
+
+add-symbol-space [-copies <N>] [-exec <FILENAME>]
+ Add a new symbol space.
+
+clone-symbol-space [-copies <N>] [ID]
+ Clone a symbol space.
+
+remove-symbol-space ID
+ Remove a symbol space.
+
* New options
set spu stop-on-load
@@ -400,6 +418,13 @@ show stack-cache
performance of remote debugging (particularly backtraces) without
affecting correctness.
+set follow-exec-mode keep|replace
+show follow-exec-mode
+ When the program execs, request to keep the previous executable'
+ symbol loaded, and load the new executable in a new symbol-space; or
+ request GDB to reuse the symbol-space and replace the previous
+ executable's symbols with the new executable.
+
* Removed commands
info forks
^ permalink raw reply [flat|nested] 16+ messages in thread