diff options
author | Pedro Alves <palves@redhat.com> | 2009-10-19 09:51:43 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2009-10-19 09:51:43 +0000 |
commit | 6c95b8df7fef5273da71c34775918c554aae0ea8 (patch) | |
tree | ad1608175364a096a3228e198c2d6dd7b3919cba /gdb/infrun.c | |
parent | 8dcb1aa7ca9439cfee66ec00a2343fbe5c35e37f (diff) | |
download | gdb-6c95b8df7fef5273da71c34775918c554aae0ea8.zip gdb-6c95b8df7fef5273da71c34775918c554aae0ea8.tar.gz gdb-6c95b8df7fef5273da71c34775918c554aae0ea8.tar.bz2 |
2009-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
Add base multi-executable/process support to GDB.
gdb/
* Makefile.in (SFILES): Add progspace.c.
(COMMON_OBS): Add progspace.o.
* progspace.h: New.
* progspace.c: New.
* breakpoint.h (struct bp_target_info) <placed_address_space>: New
field.
(struct bp_location) <pspace>: New field.
(struct breakpoint) <pspace>: 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_program_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 program 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_program_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.
(clear_syscall_counts): New.
(_initialize_breakpoint): Install it as inferior_exit observer.
* exec.h: Include "progspace.h".
(exec_bfd, exec_bfd_mtime): New defines.
(exec_close): Declare.
* exec.c: Include "gdbthread.h" and "progspace.h".
(exec_bfd, exec_bfd_mtime, current_target_sections_1): Delete.
(using_exec_ops): New.
(exec_close_1): Rename to exec_close, and make public.
(exec_close): Rename to exec_close_1, and adjust all callers. Add
description. Remove target sections and close executables from
all program 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_program_space, get_frame_address_space)
(frame_unwind_program_space): Declare.
* frame.c (struct frame_info) <pspace, aspace>: New fields.
(create_sentinel_frame): Add program space argument. Set the
pspace and aspace fields of the frame object.
(get_current_frame, create_new_frame): Adjust.
(get_frame_program_space): New.
(frame_unwind_program_space): New.
(get_frame_address_space): New.
* stack.c (print_frame_info): Adjust.
(print_frame): Use the frame's program space.
* gdbthread.h (any_live_thread_of_process): Declare.
* thread.c (any_live_thread_of_process): New.
(switch_to_thread): Switch the program space as well.
(restore_selected_frame): Don't warn if trying to restore frame
level 0.
* inferior.h: Include "progspace.h".
(detach_fork): Declare.
(struct inferior) <removable, aspace, pspace>
<vfork_parent, vfork_child, pending_detach>
<waiting_for_vfork_done>: New fields.
<terminal_info>: Remove field.
<data, num_data>: New fields.
(register_inferior_data, register_inferior_data_with_cleanup)
(clear_inferior_data, set_inferior_data, inferior_data): Declare.
(exit_inferior, exit_inferior_silent, exit_inferior_num_silent)
(inferior_appeared): Declare.
(find_inferior_pid): Typo.
(find_inferior_id, find_inferior_for_program_space): Declare.
(set_current_inferior, save_current_inferior, prune_inferiors)
(number_of_inferiors): Declare.
(inferior_list): Declare.
* inferior.c: Include "gdbcore.h" and "symfile.h".
(inferior_list): Make public.
(delete_inferior_1): Always delete thread silently.
(find_inferior_id): Make public.
(current_inferior_): New.
(current_inferior): Use it.
(set_current_inferior): New.
(restore_inferior): New.
(save_current_inferior): New.
(free_inferior): Free the per-inferior data.
(add_inferior_silent): Allocate per-inferior data.
Call inferior_appeared.
(delete_threads_of_inferior): New.
(delete_inferior_1): Adjust interface to take an inferior pointer.
(delete_inferior): Adjust.
(delete_inferior_silent): Adjust.
(exit_inferior_1): New.
(exit_inferior): New.
(exit_inferior_silent): New.
(exit_inferior_num_silent): New.
(detach_inferior): Adjust.
(inferior_appeared): New.
(discard_all_inferiors): Adjust.
(find_inferior_id): Make public. Assert pid is not zero.
(find_inferior_for_program_space): New.
(have_inferiors): Check if we have any inferior with pid not zero.
(have_live_inferiors): Go over all pushed targets looking for
process_stratum.
(prune_inferiors): New.
(number_of_inferiors): New.
(print_inferior): Add executable column. Print vfork parent/child
relationships.
(inferior_command): Adjust to cope with not running inferiors.
(remove_inferior_command): New.
(add_inferior_command): New.
(clone_inferior_command): New.
(struct inferior_data): New.
(struct inferior_data_registration): New.
(struct inferior_data_registry): New.
(inferior_data_registry): New.
(register_inferior_data_with_cleanup): New.
(register_inferior_data): New.
(inferior_alloc_data): New.
(inferior_free_data): New.
(clear_inferior_data): New.
(set_inferior_data): New.
(inferior_data): New.
(initialize_inferiors): New.
(_initialize_inferiors): Register "add-inferior",
"remove-inferior" and "clone-inferior" commands.
* objfiles.h: Include "progspace.h".
(struct objfile) <pspace>: New field.
(symfile_objfile, object_files): Don't declare.
(ALL_PSPACE_OBJFILES): New.
(ALL_PSPACE_OBJFILES_SAFE): New.
(ALL_OBJFILES, ALL_OBJFILES_SAFE): Adjust.
(ALL_PSPACE_SYMTABS): New.
(ALL_PRIMARY_SYMTABS): Adjust.
(ALL_PSPACE_PRIMARY_SYMTABS): New.
(ALL_PSYMTABS): Adjust.
(ALL_PSPACE_PSYMTABS): New.
* objfiles.c (object_files, symfile_objfile): Delete.
(struct objfile_sspace_info): New.
(objfiles_pspace_data): New.
(objfiles_pspace_data_cleanup): New.
(get_objfile_pspace_data): New.
(objfiles_changed_p): Delete.
(allocate_objfile): Set the objfile's program space. Adjust to
reference objfiles_changed_p in pspace data.
(free_objfile): Adjust to reference objfiles_changed_p in pspace
data.
(objfile_relocate): Ditto.
(update_section_map): Add pspace argument. Adjust to iterate over
objfiles in the passed in pspace.
(find_pc_section): Delete sections and num_sections statics.
Adjust to refer to program space's objfiles_changed_p. Adjust to
refer to sections and num_sections store in the objfile's pspace
data.
(objfiles_changed): Adjust to reference objfiles_changed_p in
pspace data.
(_initialize_objfiles): New.
* linespec.c (decode_all_digits, decode_dollar): Set the sal's
program space.
* source.c (current_source_pspace): New.
(get_current_source_symtab_and_line): Set the sal's program space.
(set_current_source_symtab_and_line): Set current_source_pspace.
(select_source_symtab): Ditto. Use ALL_OBJFILES.
(forget_cached_source_info): Iterate over all program spaces.
* symfile.c (clear_symtab_users): Adjust.
* symmisc.c (print_symbol_bcache_statistics): Iterate over all
program spaces.
(print_objfile_statistics): Ditto.
(maintenance_print_msymbols): Ditto.
(maintenance_print_objfiles): Ditto.
(maintenance_info_symtabs): Ditto.
(maintenance_info_psymtabs): Ditto.
* symtab.h (SYMTAB_PSPACE): New.
(struct symtab_and_line) <pspace>: New field.
* symtab.c (init_sal): Clear the sal's program space.
(find_pc_sect_symtab): Set the sal's program space. Switch thread
and space.
(append_expanded_sal): Add program space argument. Iterate over
all program spaces.
(expand_line_sal): Iterate over all program spaces. Switch
program 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_progspace): Declare.
* top.c (gdb_init): Call it.
* solist.h (struct so_list) <sspace>: New field.
* solib.h (struct program_space): Forward declare.
(solib_name_from_address): Adjust prototype.
* solib.c (so_list_head): Replace with a macro referencing the
program space.
(update_solib_list): Set the so's program space.
(solib_name_from_address): Add a program 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_pspace_data. Don't
install an inferior_exit observer anymore.
* printcmd.c (struct display) <pspace>: 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 inferior, 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
program 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 program space in sals.
(normal_stop): Prune inferiors.
(_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 pspace.
* 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 pspace 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 pspace 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 program and
address spaces.
* inf-ptrace.c (inf_ptrace_follow_fork): Copy the parent's program
and address spaces.
(inf_ptrace_attach): Set the inferior's program and address spaces.
* linux-nat.c: Include "solib.h".
(linux_child_follow_fork): Manage parent and child's program and
address spaces. Clone the parent's program space if 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 progspace.h.
(core_open): Set the inferior's program and address spaces.
* remote.c (remote_add_inferior): Set the new inferior's program
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 program 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.
* inflow.c (inferior_process_group)
(terminal_init_inferior_with_pgrp, terminal_inferior,
(terminal_ours_1, inflow_inferior_exit, copy_terminal_info)
(child_terminal_info, new_tty_postfork, set_sigint_trap): Adjust
to use per-inferior data instead of inferior->terminal_info.
(inflow_inferior_data): New.
(inflow_new_inferior): Delete.
(inflow_inferior_data_cleanup): New.
(get_inflow_inferior_data): New.
* mi/mi-interp.c (mi_new_inferior): Rename to...
(mi_inferior_appeared): ... this.
(mi_interpreter_init): Adjust.
* tui/tui-disasm.c: Include "progspace.h".
(tui_set_disassem_content): Pass an address space to
breakpoint_here_p.
* NEWS: Mention multi-program debugging support. Mention new
commands "add-inferior", "clone-inferior", "remove-inferior",
"maint info program-spaces", and new option "set
follow-exec-mode".
2009-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
gdb/doc/
* observer.texi (new_inferior): Rename to...
(inferior_appeared): ... this.
2009-10-19 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. Adjust to the inferior being
left listed after having been killed.
* 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-10-19 Pedro Alves <pedro@codesourcery.com>
Stan Shebs <stan@codesourcery.com>
gdb/doc/
* gdb.texinfo (Inferiors): Rename node to ...
(Inferiors and Programs): ... this. Mention running multiple
programs in the same debug session.
<info inferiors>: Mention the new 'Executable' column if "info
inferiors". Update examples. Document the "add-inferior",
"clone-inferior", "remove-inferior" and "maint info
program-spaces" commands.
(Process): Rename node to...
(Forks): ... this. Document "set|show follow-exec-mode".
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 398 |
1 files changed, 368 insertions, 30 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index 203ab5d..33843b2 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -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,198 @@ 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 program_space *pspace; + 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 pspace 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. */ + + pspace = inf->pspace; + aspace = inf->aspace; + inf->aspace = NULL; + inf->pspace = 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->pspace = pspace; + 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->pspace = add_program_space (maybe_new_address_space ()); + inf->aspace = inf->pspace->aspace; + inf->removable = 1; + set_current_program_space (inf->pspace); + + resume_parent = inf->vfork_parent->pid; + + /* Break the bonds. */ + inf->vfork_parent->vfork_child = NULL; + } + else + { + struct cleanup *old_chain; + struct program_space *pspace; + + /* If this is a vfork child exiting, then the pspace and + aspaces were 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/program spaces, we + go ahead and create a new one for this exiting + inferior. */ + + /* Switch to null_ptid, so that clone_program_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 + program space resets breakpoints). */ + inf->aspace = NULL; + inf->pspace = NULL; + pspace = add_program_space (maybe_new_address_space ()); + set_current_program_space (pspace); + inf->removable = 1; + clone_program_space (pspace, inf->vfork_parent->pspace); + inf->pspace = pspace; + inf->aspace = pspace->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_program_space == inf->pspace); + + 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_new[] = "new"; +static const char follow_exec_mode_same[] = "same"; +static const char *follow_exec_mode_names[] = +{ + follow_exec_mode_new, + follow_exec_mode_same, + NULL, +}; + +static const char *follow_exec_mode_string = follow_exec_mode_same; +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 +663,7 @@ follow_exec (ptid_t pid, char *execd_pathname) { 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 +685,9 @@ follow_exec (ptid_t pid, char *execd_pathname) 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 +705,9 @@ follow_exec (ptid_t pid, char *execd_pathname) 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 +726,6 @@ follow_exec (ptid_t pid, char *execd_pathname) 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 +734,30 @@ follow_exec (ptid_t pid, char *execd_pathname) previous incarnation of this process. */ no_shared_libraries (NULL, 0); + if (follow_exec_mode_string == follow_exec_mode_new) + { + struct program_space *pspace; + struct inferior *new_inf; + + /* The user wants to keep the old inferior and program spaces + around. Create a new fresh one, and switch to it. */ + + inf = add_inferior (current_inferior ()->pid); + pspace = add_program_space (maybe_new_address_space ()); + inf->pspace = pspace; + inf->aspace = pspace->aspace; + + exit_inferior_num_silent (current_inferior ()->num); + + set_current_inferior (inf); + set_current_program_space (pspace); + } + + gdb_assert (current_program_space == inf->pspace); + + /* 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 +1191,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) struct regcache *regcache; struct gdbarch *gdbarch; CORE_ADDR actual_pc; + struct address_space *aspace; head = displaced_step_request_queue; ptid = head->ptid; @@ -979,8 +1202,9 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal) 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, @@ -1145,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; @@ -1170,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 +1512,7 @@ a command like `return' or `jump' to continue execution.")); /* 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 +1586,26 @@ clear_proceed_status_callback (struct thread_info *tp, void *data) 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 +1667,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 +1706,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) 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 +1721,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) regcache = get_current_regcache (); gdbarch = get_regcache_arch (regcache); + aspace = get_regcache_aspace (regcache); pc = regcache_read_pc (regcache); if (step > 0) @@ -1500,7 +1731,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) 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 @@ -2231,6 +2462,7 @@ adjust_pc_after_break (struct execution_control_state *ecs) { 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 @@ -2296,6 +2528,8 @@ adjust_pc_after_break (struct execution_control_state *ecs) 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) @@ -2309,8 +2543,8 @@ adjust_pc_after_break (struct execution_control_state *ecs) 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) @@ -2411,7 +2645,9 @@ handle_syscall_event (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n", syscall_number); - ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); + ecs->event_thread->stop_bpstat + = bpstat_stop_status (get_regcache_aspace (regcache), + stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat); if (!ecs->random_signal) @@ -2622,6 +2858,9 @@ handle_inferior_event (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n"); inferior_ptid = ecs->ptid; + set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid))); + set_current_program_space (current_inferior ()->pspace); + handle_vfork_child_exec_or_exit (0); target_terminal_ours (); /* Must do this before mourn anyway */ print_stop_reason (EXITED, ecs->ws.value.integer); @@ -2640,6 +2879,9 @@ handle_inferior_event (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n"); inferior_ptid = ecs->ptid; + set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid))); + set_current_program_space (current_inferior ()->pspace); + handle_vfork_child_exec_or_exit (0); stop_print_frame = 0; target_terminal_ours (); /* Must do this before mourn anyway */ @@ -2696,19 +2938,45 @@ handle_inferior_event (struct execution_control_state *ecs) 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; @@ -2721,6 +2989,22 @@ handle_inferior_event (struct execution_control_state *ecs) 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"); @@ -2733,12 +3017,17 @@ handle_inferior_event (struct execution_control_state *ecs) 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 @@ -2929,14 +3218,15 @@ targets should add new threads to the thread list themselves in non-stop mode.") 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) @@ -3223,7 +3513,8 @@ targets should add new threads to the thread list themselves in non-stop mode.") 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)) @@ -3280,8 +3571,10 @@ targets should add new threads to the thread list themselves in non-stop mode.") } /* 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; @@ -3812,6 +4105,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); struct symtab_and_line sr_sal; init_sal (&sr_sal); sr_sal.pc = pc_after_resolver; + sr_sal.pspace = get_frame_program_space (frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, null_frame_id); @@ -3922,8 +4216,9 @@ infrun: not switching back to stepped thread, it has vanished\n"); /* 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.pspace = get_frame_program_space (frame); + insert_step_resume_breakpoint_at_sal (gdbarch, + sr_sal, null_frame_id); } else insert_step_resume_breakpoint_at_caller (frame); @@ -3948,6 +4243,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); struct symtab_and_line sr_sal; init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; + sr_sal.pspace = get_frame_program_space (frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, null_frame_id); @@ -3994,6 +4290,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); struct symtab_and_line sr_sal; init_sal (&sr_sal); sr_sal.pc = ecs->stop_func_start; + sr_sal.pspace = get_frame_program_space (frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, null_frame_id); } @@ -4059,6 +4356,7 @@ infrun: not switching back to stepped thread, it has vanished\n"); init_sal (&sr_sal); /* initialize to zeroes */ sr_sal.pc = real_stop_pc; sr_sal.section = find_pc_overlay (sr_sal.pc); + sr_sal.pspace = get_frame_program_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 @@ -4338,6 +4636,7 @@ handle_step_into_function (struct gdbarch *gdbarch, 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.pspace = get_frame_program_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 @@ -4429,6 +4728,7 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_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.pspace = get_frame_program_space (return_frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, get_stack_frame_id (return_frame)); @@ -4465,6 +4765,7 @@ insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame) 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.pspace = frame_unwind_program_space (next_frame); insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal, frame_unwind_caller_id (next_frame)); @@ -4968,6 +5269,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 inferiors that are no + longer needed. Keeping those around slows down things linearly. + Note that this never removes the current inferior. */ + prune_inferiors (); } static int @@ -6039,6 +6345,30 @@ By default, the debugger will follow the parent process."), 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 program image of a process.\n\ +\n\ +follow-exec-mode can be:\n\ +\n\ + new - the debugger creates a new inferior and rebinds the process \n\ +to this new inferior. The program the process was running before\n\ +the exec call can be restarted afterwards by restarting the original\n\ +inferior.\n\ +\n\ + same - the debugger keeps the process bound to the same inferior.\n\ +The new executable image replaces the previous executable loaded in\n\ +the inferior. Restarting the inferior after the exec call restarts\n\ +the executable the process was running after the exec call.\n\ +\n\ +By default, the debugger will use the same inferior."), + 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."), _("\ @@ -6097,6 +6427,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); |