This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: Actual support for tracing forks on GNU/Linux


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 <drow@mvista.com>
> 
>    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  <drow@mvista.com>

	* 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 */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]