From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11294 invoked by alias); 17 Aug 2003 18:22:47 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 11287 invoked from network); 17 Aug 2003 18:22:45 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sources.redhat.com with SMTP; 17 Aug 2003 18:22:45 -0000 Received: from drow by nevyn.them.org with local (Exim 4.20 #1 (Debian)) id 19oSAv-0001ti-Cs for ; Sun, 17 Aug 2003 14:22:45 -0400 Date: Sun, 17 Aug 2003 18:22:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Subject: Re: RFA: Actual support for tracing forks on GNU/Linux Message-ID: <20030817182245.GA24800@nevyn.them.org> Mail-Followup-To: gdb-patches@sources.redhat.com References: <20030618232942.GA982@nevyn.them.org> <20030628163444.GB9716@nevyn.them.org> <20030709215713.GA25331@nevyn.them.org> <20030724184849.GC1842@nevyn.them.org> <200308101611.h7AGBfnh058626@elgar.kettenis.dyndns.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200308101611.h7AGBfnh058626@elgar.kettenis.dyndns.org> User-Agent: Mutt/1.5.1i X-SW-Source: 2003-08/txt/msg00271.txt.bz2 On Sun, Aug 10, 2003 at 06:11:41PM +0200, Mark Kettenis wrote: > Date: Thu, 24 Jul 2003 14:48:49 -0400 > From: Daniel Jacobowitz > > Ping. > > Sorry Daniel for not responding earlier. I've had almost no time to > spend on hacking since the second half of june and I've just returned > from a vacation in Finland. Anyway, I do have a few comments: > > * I'm not very enthousiastic about the staggering of > CHILD_POST_STARTUP_INFERIOR and LINUX_CHILD_POST_STARTUP_INFERIOR, > especially since it infects i386-nat.c. However, I'm pretty sure > there isn't a better alternative that doesn't involve redisigning > the target vector :-(. I'd appreciate though if you could stick in > a comment somewhere that says this is really ugly. > > * The changes to lin-lwp.c seem pretty much OK to me. > > So I think this can go in. Thanks. I agree with your reaction to CHILD_POST_STARTUP_INFERIOR, so I've clarified the comment. Also needed to move a few prototypes to linux-nat.h. -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer 2003-08-17 Daniel Jacobowitz * Makefile.in (i386-linux-nat.o): Update dependencies. * config/i386/nm-linux.h (LINUX_CHILD_POST_STARTUP_INFERIOR): Define. * config/nm-linux.h (CHILD_POST_STARTUP_INFERIOR, CHILD_POST_ATTACH) (CHILD_FOLLOW_FORK, KILL_INFERIOR): Define. * i386-linux-nat.c: Include "linux-nat.h". (child_post_startup_inferior): New function. * i386-nat.c (child_post_startup_inferior): Wrap in #ifdef. * infptrace.c (kill_inferior): Wrap in #ifdef. * lin-lwp.c (lin_lwp_attach_lwp): Call child_post_attach after attaching to each LWP. (child_wait, lin_lwp_wait): Call linux_handle_extended_wait. (init_lin_lwp_ops): Fill in some more operations. * linux-nat.h (linux_enable_event_reporting) (linux_handle_extended_wait, linux_child_post_startup_inferior): New prototypes. * linux-nat.c (linux_enable_event_reporting): New function. (child_post_attach, linux_child_post_startup_inferior) (child_post_startup_inferior, child_follow_fork) (linux_handle_extended_wait, kill_inferior): New functions. Index: Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.429 diff -u -p -r1.429 Makefile.in --- Makefile.in 16 Aug 2003 17:49:12 -0000 1.429 +++ Makefile.in 17 Aug 2003 17:46:09 -0000 @@ -1843,7 +1843,7 @@ i386-interix-tdep.o: i386-interix-tdep.c i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(gregset_h) \ $(i387_tdep_h) $(i386_tdep_h) $(i386_linux_tdep_h) \ - $(gdb_proc_service_h) + $(gdb_proc_service_h) $(linux_nat_h) i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \ $(value_h) $(regcache_h) $(inferior_h) $(reggroups_h) $(symtab_h) \ $(symfile_h) $(objfiles_h) $(solib_svr4_h) $(osabi_h) $(i386_tdep_h) \ Index: i386-linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v retrieving revision 1.47 diff -u -p -r1.47 i386-linux-nat.c --- i386-linux-nat.c 4 Jun 2003 20:51:29 -0000 1.47 +++ i386-linux-nat.c 17 Aug 2003 17:46:10 -0000 @@ -23,6 +23,7 @@ #include "inferior.h" #include "gdbcore.h" #include "regcache.h" +#include "linux-nat.h" #include "gdb_assert.h" #include "gdb_string.h" @@ -889,6 +890,13 @@ child_resume (ptid_t ptid, int step, enu if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1) perror_with_name ("ptrace"); +} + +void +child_post_startup_inferior (ptid_t ptid) +{ + i386_cleanup_dregs (); + linux_child_post_startup_inferior (ptid); } Index: i386-nat.c =================================================================== RCS file: /cvs/src/src/gdb/i386-nat.c,v retrieving revision 1.5 diff -u -p -r1.5 i386-nat.c --- i386-nat.c 4 Jul 2002 12:32:28 -0000 1.5 +++ i386-nat.c 17 Aug 2003 17:46:10 -0000 @@ -230,6 +230,7 @@ i386_cleanup_dregs (void) dr_status_mirror = 0; } +#ifndef LINUX_CHILD_POST_STARTUP_INFERIOR /* Reset all debug registers at each new startup to avoid missing watchpoints after restart. */ void @@ -237,6 +238,7 @@ child_post_startup_inferior (ptid_t ptid { i386_cleanup_dregs (); } +#endif /* LINUX_CHILD_POST_STARTUP_INFERIOR */ /* Print the values of the mirrored debug registers. This is called when maint_show_dr is non-zero. To set that Index: infptrace.c =================================================================== RCS file: /cvs/src/src/gdb/infptrace.c,v retrieving revision 1.26 diff -u -p -r1.26 infptrace.c --- infptrace.c 22 May 2003 15:46:20 -0000 1.26 +++ infptrace.c 17 Aug 2003 17:46:10 -0000 @@ -208,6 +208,7 @@ ptrace_wait (ptid_t ptid, int *status) return wstate; } +#ifndef KILL_INFERIOR void kill_inferior (void) { @@ -229,6 +230,7 @@ kill_inferior (void) ptrace_wait (null_ptid, &status); target_mourn_inferior (); } +#endif /* KILL_INFERIOR */ #ifndef CHILD_RESUME Index: lin-lwp.c =================================================================== RCS file: /cvs/src/src/gdb/lin-lwp.c,v retrieving revision 1.47 diff -u -p -r1.47 lin-lwp.c --- lin-lwp.c 19 Jun 2003 22:52:03 -0000 1.47 +++ lin-lwp.c 17 Aug 2003 17:46:10 -0000 @@ -324,6 +324,8 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver gdb_assert (pid == GET_LWP (ptid) && WIFSTOPPED (status) && WSTOPSIG (status)); + child_post_attach (pid); + lp->stopped = 1; if (debug_lin_lwp) @@ -1067,6 +1069,10 @@ child_wait (ptid_t ptid, struct target_w return minus_one_ptid; } + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + return linux_handle_extended_wait (pid, status, ourstatus); + store_waitstatus (ourstatus, status); return pid_to_ptid (pid); } @@ -1488,6 +1494,14 @@ retry: else trap_ptid = null_ptid; + /* Handle GNU/Linux's extended waitstatus for trace events. */ + if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + { + linux_handle_extended_wait (ptid_get_pid (trap_ptid), + status, ourstatus); + return trap_ptid; + } + store_waitstatus (ourstatus, status); return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid))); } @@ -1657,6 +1671,12 @@ init_lin_lwp_ops (void) lin_lwp_ops.to_mourn_inferior = lin_lwp_mourn_inferior; lin_lwp_ops.to_thread_alive = lin_lwp_thread_alive; lin_lwp_ops.to_pid_to_str = lin_lwp_pid_to_str; + lin_lwp_ops.to_post_startup_inferior = child_post_startup_inferior; + lin_lwp_ops.to_post_attach = child_post_attach; + lin_lwp_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint; + lin_lwp_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint; + lin_lwp_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint; + lin_lwp_ops.to_stratum = thread_stratum; lin_lwp_ops.to_has_thread_control = tc_schedlock; lin_lwp_ops.to_magic = OPS_MAGIC; Index: linux-nat.c =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.c,v retrieving revision 1.3 diff -u -p -r1.3 linux-nat.c --- linux-nat.c 19 Jun 2003 22:52:03 -0000 1.3 +++ linux-nat.c 17 Aug 2003 17:46:10 -0000 @@ -56,6 +56,8 @@ #define __WALL 0x40000000 /* Wait for any child. */ #endif +extern struct target_ops child_ops; + struct simple_pid_list { int pid; @@ -189,13 +191,147 @@ linux_supports_tracefork (void) } +void +linux_enable_event_reporting (ptid_t ptid) +{ + int pid = ptid_get_pid (ptid); + int options; + + if (! linux_supports_tracefork ()) + return; + + options = PTRACE_O_TRACEFORK; + + ptrace (PTRACE_SETOPTIONS, pid, 0, options); +} + +void +child_post_attach (int pid) +{ + linux_enable_event_reporting (pid_to_ptid (pid)); +} + +void +linux_child_post_startup_inferior (ptid_t ptid) +{ + linux_enable_event_reporting (ptid); +} + +#ifndef LINUX_CHILD_POST_STARTUP_INFERIOR +void +child_post_startup_inferior (ptid_t ptid) +{ + linux_child_post_startup_inferior (ptid); +} +#endif + int -child_insert_fork_catchpoint (int pid) +child_follow_fork (int follow_child) { - if (linux_supports_tracefork ()) - error ("Fork catchpoints have not been implemented yet."); + ptid_t last_ptid; + struct target_waitstatus last_status; + int parent_pid, child_pid; + + get_last_target_status (&last_ptid, &last_status); + parent_pid = ptid_get_pid (last_ptid); + child_pid = last_status.value.related_pid; + + if (! follow_child) + { + /* We're already attached to the parent, by default. */ + + /* Before detaching from the child, remove all breakpoints from + it. (This won't actually modify the breakpoint list, but will + physically remove the breakpoints from the child.) */ + detach_breakpoints (child_pid); + + fprintf_filtered (gdb_stdout, + "Detaching after fork from child process %d.\n", + child_pid); + + ptrace (PTRACE_DETACH, child_pid, 0, 0); + } else + { + char child_pid_spelling[40]; + + /* Needed to keep the breakpoint lists in sync. */ + detach_breakpoints (child_pid); + + /* Before detaching from the parent, remove all breakpoints from it. */ + remove_breakpoints (); + + fprintf_filtered (gdb_stdout, + "Attaching after fork to child process %d.\n", + child_pid); + + target_detach (NULL, 0); + + inferior_ptid = pid_to_ptid (child_pid); + push_target (&child_ops); + + /* Reset breakpoints in the child as appropriate. */ + follow_inferior_reset_breakpoints (); + } + + return 0; +} + +ptid_t +linux_handle_extended_wait (int pid, int status, + struct target_waitstatus *ourstatus) +{ + int event = status >> 16; + + if (event == PTRACE_EVENT_CLONE) + internal_error (__FILE__, __LINE__, + "unexpected clone event"); + + if (event == PTRACE_EVENT_FORK) + { + unsigned long new_pid; + int ret; + + ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid); + + /* If we haven't already seen the new PID stop, wait for it now. */ + if (! pull_pid_from_list (&stopped_pids, new_pid)) + { + /* The new child has a pending SIGSTOP. We can't affect it until it + hits the SIGSTOP, but we're already attached. + + It won't be a clone (we didn't ask for clones in the event mask) + so we can just call waitpid and wait for the SIGSTOP. */ + do { + ret = waitpid (new_pid, &status, 0); + } while (ret == -1 && errno == EINTR); + if (ret == -1) + perror_with_name ("waiting for new child"); + else if (ret != new_pid) + internal_error (__FILE__, __LINE__, + "wait returned unexpected PID %d", ret); + else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP) + internal_error (__FILE__, __LINE__, + "wait returned unexpected status 0x%x", status); + } + + ourstatus->kind = TARGET_WAITKIND_FORKED; + ourstatus->value.related_pid = new_pid; + return inferior_ptid; + } + + internal_error (__FILE__, __LINE__, + "unknown ptrace event %d", event); +} + + +int +child_insert_fork_catchpoint (int pid) +{ + if (! linux_supports_tracefork ()) error ("Your system does not support fork catchpoints."); + + return 0; } int @@ -216,4 +352,43 @@ child_insert_exec_catchpoint (int pid) error ("Your system does not support exec catchpoints."); } +void +kill_inferior (void) +{ + int status; + int pid = PIDGET (inferior_ptid); + struct target_waitstatus last; + ptid_t last_ptid; + int ret; + + if (pid == 0) + return; + + /* If we're stopped while forking and we haven't followed yet, kill the + other task. We need to do this first because the parent will be + sleeping if this is a vfork. */ + + get_last_target_status (&last_ptid, &last); + if (last.kind == TARGET_WAITKIND_FORKED + || last.kind == TARGET_WAITKIND_VFORKED) + { + ptrace (PT_KILL, last.value.related_pid); + ptrace_wait (null_ptid, &status); + } + + /* Kill the current process. */ + ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0); + ret = ptrace_wait (null_ptid, &status); + + /* We might get a SIGCHLD instead of an exit status. This is + aggravated by the first kill above - a child has just died. */ + + while (ret == pid && WIFSTOPPED (status)) + { + ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0); + ret = ptrace_wait (null_ptid, &status); + } + + target_mourn_inferior (); +} Index: linux-nat.h =================================================================== RCS file: /cvs/src/src/gdb/linux-nat.h,v retrieving revision 1.2 diff -u -p -r1.2 linux-nat.h --- linux-nat.h 20 Jun 2003 04:04:43 -0000 1.2 +++ linux-nat.h 17 Aug 2003 17:46:10 -0000 @@ -65,7 +65,12 @@ extern int linux_proc_xfer_memory (CORE_ int write, struct mem_attrib *attrib, struct target_ops *target); +/* linux-nat functions for handling fork events. */ extern void linux_record_stopped_pid (int pid); +extern void linux_enable_event_reporting (ptid_t ptid); +extern ptid_t linux_handle_extended_wait (int pid, int status, + struct target_waitstatus *ourstatus); +extern void linux_child_post_startup_inferior (ptid_t ptid); /* Iterator function for lin-lwp's lwp list. */ struct lwp_info *iterate_over_lwps (int (*callback) (struct lwp_info *, Index: config/nm-linux.h =================================================================== RCS file: /cvs/src/src/gdb/config/nm-linux.h,v retrieving revision 1.18 diff -u -p -r1.18 nm-linux.h --- config/nm-linux.h 19 Jun 2003 22:52:04 -0000 1.18 +++ config/nm-linux.h 17 Aug 2003 17:46:10 -0000 @@ -73,3 +73,7 @@ extern void lin_thread_get_thread_signal #define CHILD_INSERT_FORK_CATCHPOINT #define CHILD_INSERT_VFORK_CATCHPOINT #define CHILD_INSERT_EXEC_CATCHPOINT +#define CHILD_POST_STARTUP_INFERIOR +#define CHILD_POST_ATTACH +#define CHILD_FOLLOW_FORK +#define KILL_INFERIOR Index: config/i386/nm-linux.h =================================================================== RCS file: /cvs/src/src/gdb/config/i386/nm-linux.h,v retrieving revision 1.19 diff -u -p -r1.19 nm-linux.h --- config/i386/nm-linux.h 9 Nov 2002 21:31:12 -0000 1.19 +++ config/i386/nm-linux.h 17 Aug 2003 17:46:10 -0000 @@ -82,4 +82,13 @@ extern int cannot_store_register (int re /* Override child_resume in `infptrace.c'. */ #define CHILD_RESUME +/* `linux-nat.c' and `i386-nat.c' have their own versions of + child_post_startup_inferior. Define this to use the copy in + `i386-linux-nat.c' instead, which calls both. + + NOTE drow/2003-08-17: This is ugly beyond words, but properly + fixing it will require some serious surgery. Ideally the target + stack could be used for this. */ +#define LINUX_CHILD_POST_STARTUP_INFERIOR + #endif /* nm-linux.h */