diff options
author | Don Breazeal <donb@codesourcery.com> | 2014-09-30 11:01:57 -0700 |
---|---|---|
committer | Don Breazeal <donb@codesourcery.com> | 2014-09-30 11:01:57 -0700 |
commit | d83ad864a285fe3127e1a98830197e8461ad2745 (patch) | |
tree | 17fc116484b87e08c0a992063513490208c3e1ef /gdb/linux-nat.c | |
parent | 63b434a4374b61aa34b095a789cd0d03b2a5a526 (diff) | |
download | gdb-d83ad864a285fe3127e1a98830197e8461ad2745.zip gdb-d83ad864a285fe3127e1a98830197e8461ad2745.tar.gz gdb-d83ad864a285fe3127e1a98830197e8461ad2745.tar.bz2 |
Refactor native follow-fork.
This patch reorganizes the code that implements follow-fork and
detach-on-fork in preparation for implementation of those features for the
extended-remote target. The function linux-nat.c:linux_child_follow_fork
contained target-independent code mixed in with target-dependent code. The
target-independent pieces need to be accessible for the host-side
implementation of follow-fork for extended-remote Linux targets.
The changes are fairly mechanical. A new routine, follow_fork_inferior,
is implemented in infrun.c, containing those parts of
linux_child_follow_fork that manage inferiors and the inferior list. The
parts of linux_child_follow_fork that deal with LWPs and target-specifics
were left in-place. Although the order of some operations was changed, the
resulting functionality was not.
Modifications were made to the other native target follow-fork functions,
inf_ttrace_follow_fork and inf_ptrace_follow_fork, that should allow them
to work with follow_fork_inferior. Some other adjustments were necessary
in inf-ttrace.c. The changes to inf-ttrace.c and inf-ptrace.c were not
tested.
gdb/ChangeLog:
* inf-ptrace.c (inf_ptrace_follow_fork): Remove target-independent
code so as to work with follow_fork_inferior.
* inf-ttrace.c (inf_ttrace_follow_fork): Ditto.
(inf_ttrace_create_inferior): Remove reference to
inf_ttrace_vfork_ppid.
(inf_ttrace_attach): Ditto.
(inf_ttrace_detach): Ditto.
(inf_ttrace_kill): Use current_inferior instead of
inf_ttrace_vfork_ppid.
(inf_ttrace_wait): Eliminate use of inf_ttrace_vfork_ppid, report
TARGET_WAITKIND_VFORK_DONE event, delete HACK that switched the
inferior away from the parent.
* infrun.c (follow_fork): Call follow_fork_inferior instead of
target_follow_fork.
(follow_fork_inferior): New function.
(follow_inferior_reset_breakpoints): Make function static.
* infrun.h (follow_inferior_reset_breakpoints): Remove declaration.
* linux-nat.c (linux_child_follow_fork): Move target-independent
code to infrun.c:follow_fork_inferior.
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 243 |
1 files changed, 26 insertions, 217 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 7f0f4f8..60f6a84 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -54,7 +54,6 @@ #include <sys/types.h> #include <dirent.h> #include "xml-support.h" -#include "terminal.h" #include <sys/vfs.h> #include "solib.h" #include "nat/linux-osdata.h" @@ -369,79 +368,41 @@ delete_lwp_cleanup (void *lp_voidp) delete_lwp (lp->ptid); } +/* Target hook for follow_fork. On entry inferior_ptid must be the + ptid of the followed inferior. At return, inferior_ptid will be + unchanged. */ + static int linux_child_follow_fork (struct target_ops *ops, int follow_child, int detach_fork) { - int has_vforked; - int parent_pid, child_pid; - - has_vforked = (inferior_thread ()->pending_follow.kind - == TARGET_WAITKIND_VFORKED); - parent_pid = ptid_get_lwp (inferior_ptid); - if (parent_pid == 0) - parent_pid = ptid_get_pid (inferior_ptid); - child_pid - = ptid_get_pid (inferior_thread ()->pending_follow.value.related_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")); - /* FIXME output string > 80 columns. */ - return 1; - } - - if (! follow_child) + if (!follow_child) { struct lwp_info *child_lp = NULL; + int status = W_STOPCODE (0); + struct cleanup *old_chain; + int has_vforked; + int parent_pid, child_pid; + + has_vforked = (inferior_thread ()->pending_follow.kind + == TARGET_WAITKIND_VFORKED); + parent_pid = ptid_get_lwp (inferior_ptid); + if (parent_pid == 0) + parent_pid = ptid_get_pid (inferior_ptid); + child_pid + = ptid_get_pid (inferior_thread ()->pending_follow.value.related_pid); + /* We're already attached to the parent, by default. */ + old_chain = save_inferior_ptid (); + inferior_ptid = ptid_build (child_pid, child_pid, 0); + child_lp = add_lwp (inferior_ptid); + child_lp->stopped = 1; + child_lp->last_resume_kind = resume_stop; /* Detach new forked process? */ if (detach_fork) { - struct cleanup *old_chain; - int status = W_STOPCODE (0); - - /* 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 (ptid_get_pid (inferior_ptid)); - } - - if (info_verbose || debug_linux_nat) - { - target_terminal_ours (); - fprintf_filtered (gdb_stdlog, - "Detaching after fork from " - "child process %d.\n", - child_pid); - } - - old_chain = save_inferior_ptid (); - inferior_ptid = ptid_build (child_pid, child_pid, 0); - - child_lp = add_lwp (inferior_ptid); - child_lp->stopped = 1; - child_lp->last_resume_kind = resume_stop; make_cleanup (delete_lwp_cleanup, child_lp); if (linux_nat_prepare_to_resume != NULL) @@ -476,86 +437,20 @@ holding the child stopped. Try \"set detach-on-fork\" or \ ptrace (PTRACE_DETACH, child_pid, 0, signo); } + /* Resets value of inferior_ptid to parent ptid. */ do_cleanups (old_chain); } else { - struct inferior *parent_inf, *child_inf; - struct cleanup *old_chain; - - /* Add process to GDB's tables. */ - child_inf = add_inferior (child_pid); - - parent_inf = current_inferior (); - child_inf->attach_flag = parent_inf->attach_flag; - copy_terminal_info (child_inf, parent_inf); - child_inf->gdbarch = parent_inf->gdbarch; - copy_inferior_target_desc_info (child_inf, parent_inf); - - old_chain = save_inferior_ptid (); - save_current_program_space (); - - inferior_ptid = ptid_build (child_pid, child_pid, 0); - add_thread (inferior_ptid); - child_lp = add_lwp (inferior_ptid); - child_lp->stopped = 1; - child_lp->last_resume_kind = resume_stop; - child_inf->symfile_flags = SYMFILE_NO_READ; - - /* If this is a vfork child, then the address-space is - shared with the parent. */ - if (has_vforked) - { - child_inf->pspace = parent_inf->pspace; - 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->pspace = add_program_space (child_inf->aspace); - child_inf->removable = 1; - set_current_program_space (child_inf->pspace); - clone_program_space (child_inf->pspace, parent_inf->pspace); - - /* 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 (0); - } - /* Let the thread_db layer learn about this new process. */ check_for_thread_db (); - - do_cleanups (old_chain); } + do_cleanups (old_chain); + if (has_vforked) { struct lwp_info *parent_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; - parent_inf->pspace->breakpoints_not_allowed = detach_fork; parent_lp = find_lwp_pid (pid_to_ptid (parent_pid)); gdb_assert (linux_supports_tracefork () >= 0); @@ -628,98 +523,12 @@ holding the child stopped. Try \"set detach-on-fork\" or \ } else { - struct inferior *parent_inf, *child_inf; struct lwp_info *child_lp; - struct program_space *parent_pspace; - - if (info_verbose || debug_linux_nat) - { - target_terminal_ours (); - 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 - doesn't unpush the target. */ - - child_inf = add_inferior (child_pid); - - parent_inf = current_inferior (); - child_inf->attach_flag = parent_inf->attach_flag; - copy_terminal_info (child_inf, parent_inf); - child_inf->gdbarch = parent_inf->gdbarch; - copy_inferior_target_desc_info (child_inf, parent_inf); - - parent_pspace = parent_inf->pspace; - - /* 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 debugging it. Otherwise, detach the parent now; we'll - want to reuse it's program/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) - { - 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 program space, and - informing the solib layer about this new process. */ - - inferior_ptid = ptid_build (child_pid, child_pid, 0); - add_thread (inferior_ptid); child_lp = add_lwp (inferior_ptid); child_lp->stopped = 1; child_lp->last_resume_kind = resume_stop; - /* 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 program/address spaces. */ - if (has_vforked || detach_fork) - { - child_inf->pspace = parent_pspace; - child_inf->aspace = child_inf->pspace->aspace; - } - else - { - child_inf->aspace = new_address_space (); - child_inf->pspace = add_program_space (child_inf->aspace); - child_inf->removable = 1; - child_inf->symfile_flags = SYMFILE_NO_READ; - set_current_program_space (child_inf->pspace); - clone_program_space (child_inf->pspace, parent_pspace); - - /* 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 (0); - } - /* Let the thread_db layer learn about this new process. */ check_for_thread_db (); } |