Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [commit] Last major piece of fork tracing - vfork/exec
@ 2003-08-17 20:19 Daniel Jacobowitz
  2003-08-18 15:46 ` Andrew Cagney
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2003-08-17 20:19 UTC (permalink / raw)
  To: gdb-patches

This patch is the last major piece of fork tracing: support for vfork and
exec.  I have not enabled the code in infrun which attempts to automatically
load the new executable, because I'm not happy with how it works, and
because it isn't necessary for this to be useful.

I'll move this to the branch in a day or two if there are no problems.
I suppose fixing up the expected output in the testsuite is next...

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-08-17  Daniel Jacobowitz  <drow@mvista.com>

	* linux-nat.c (PTRACE_O_TRACEVFORKDONE, PTRACE_O_TRACEEXIT): Define.
	(PTRACE_EVENT_VFORKDONE, PTRACE_EVENT_EXIT): Define.
	(linux_parent_pid, linux_supports_tracevforkdone_flag): New variable.
	(linux_test_for_tracefork): Set linux_supports_tracevforkdone_flag.
	(linux_supports_tracevforkdone): New function.
	(linux_enable_event_reporting): Enable TRACEVFORK, TRACEEXEC, and
	TRACEVFORKDONE.
	(child_follow_fork): Handle vfork.
	(linux_handle_extended_wait): Likewise.  Also handle exec.
	(child_insert_vfork_catchpoint, child_insert_exec_catchpoint): Enable.
	* NEWS: Mention fork tracing.

Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.4
diff -u -p -r1.4 linux-nat.c
--- linux-nat.c	17 Aug 2003 18:22:25 -0000	1.4
+++ linux-nat.c	17 Aug 2003 19:23:20 -0000
@@ -40,12 +40,16 @@
 #define PTRACE_O_TRACEVFORK	0x00000004
 #define PTRACE_O_TRACECLONE	0x00000008
 #define PTRACE_O_TRACEEXEC	0x00000010
+#define PTRACE_O_TRACEVFORKDONE	0x00000020
+#define PTRACE_O_TRACEEXIT	0x00000040
 
 /* Wait extended result codes for the above trace options.  */
 #define PTRACE_EVENT_FORK	1
 #define PTRACE_EVENT_VFORK	2
 #define PTRACE_EVENT_CLONE	3
 #define PTRACE_EVENT_EXEC	4
+#define PTRACE_EVENT_VFORKDONE	5
+#define PTRACE_EVENT_EXIT	6
 
 #endif /* PTRACE_EVENT_FORK */
 
@@ -58,6 +62,8 @@
 
 extern struct target_ops child_ops;
 
+static int linux_parent_pid;
+
 struct simple_pid_list
 {
   int pid;
@@ -70,6 +76,11 @@ struct simple_pid_list *stopped_pids;
 
 static int linux_supports_tracefork_flag = -1;
 
+/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
+   PTRACE_O_TRACEVFORKDONE.  */
+
+static int linux_supports_tracevforkdone_flag = -1;
+
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -155,6 +166,11 @@ linux_test_for_tracefork (void)
       return;
     }
 
+  /* Check whether PTRACE_O_TRACEVFORKDONE is available.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0,
+		PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
+  linux_supports_tracevforkdone_flag = (ret == 0);
+
   ptrace (PTRACE_CONT, child_pid, 0, 0);
   ret = waitpid (child_pid, &status, 0);
   if (ret == child_pid && WIFSTOPPED (status)
@@ -190,6 +206,14 @@ linux_supports_tracefork (void)
   return linux_supports_tracefork_flag;
 }
 
+static int
+linux_supports_tracevforkdone (void)
+{
+  if (linux_supports_tracefork_flag == -1)
+    linux_test_for_tracefork ();
+  return linux_supports_tracevforkdone_flag;
+}
+
 \f
 void
 linux_enable_event_reporting (ptid_t ptid)
@@ -200,7 +224,12 @@ linux_enable_event_reporting (ptid_t pti
   if (! linux_supports_tracefork ())
     return;
 
-  options = PTRACE_O_TRACEFORK;
+  options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC;
+  if (linux_supports_tracevforkdone ())
+    options |= PTRACE_O_TRACEVFORKDONE;
+
+  /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
+     read-only process state.  */
 
   ptrace (PTRACE_SETOPTIONS, pid, 0, options);
 }
@@ -230,9 +259,11 @@ child_follow_fork (int follow_child)
 {
   ptid_t last_ptid;
   struct target_waitstatus last_status;
+  int has_vforked;
   int parent_pid, child_pid;
 
   get_last_target_status (&last_ptid, &last_status);
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
   parent_pid = ptid_get_pid (last_ptid);
   child_pid = last_status.value.related_pid;
 
@@ -243,6 +274,8 @@ child_follow_fork (int follow_child)
       /* 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.) */
+      /* If we vforked this will remove the breakpoints from the parent
+	 also, but they'll be reinserted below.  */
       detach_breakpoints (child_pid);
 
       fprintf_filtered (gdb_stdout,
@@ -250,13 +283,67 @@ child_follow_fork (int follow_child)
 			child_pid);
 
       ptrace (PTRACE_DETACH, child_pid, 0, 0);
+
+      if (has_vforked)
+	{
+	  if (linux_supports_tracevforkdone ())
+	    {
+	      int status;
+
+	      ptrace (PTRACE_CONT, parent_pid, 0, 0);
+	      waitpid (parent_pid, &status, __WALL);
+	      if ((status >> 16) != PTRACE_EVENT_VFORKDONE)
+		warning ("Unexpected waitpid result %06x when waiting for "
+			 "vfork-done", status);
+	    }
+	  else
+	    {
+	      /* We can't insert breakpoints until the child has
+		 finished with the shared memory region.  We need to
+		 wait until that happens.  Ideal would be to just
+		 call:
+		 - ptrace (PTRACE_SYSCALL, parent_pid, 0, 0);
+		 - waitpid (parent_pid, &status, __WALL);
+		 However, most architectures can't handle a syscall
+		 being traced on the way out if it wasn't traced on
+		 the way in.
+
+		 We might also think to loop, continuing the child
+		 until it exits or gets a SIGTRAP.  One problem is
+		 that the child might call ptrace with PTRACE_TRACEME.
+
+		 There's no simple and reliable way to figure out when
+		 the vforked child will be done with its copy of the
+		 shared memory.  We could step it out of the syscall,
+		 two instructions, let it go, and then single-step the
+		 parent once.  When we have hardware single-step, this
+		 would work; with software single-step it could still
+		 be made to work but we'd have to be able to insert
+		 single-step breakpoints in the child, and we'd have
+		 to insert -just- the single-step breakpoint in the
+		 parent.  Very awkward.
+
+		 In the end, the best we can do is to make sure it
+		 runs for a little while.  Hopefully it will be out of
+		 range of any breakpoints we reinsert.  Usually this
+		 is only the single-step breakpoint at vfork's return
+		 point.  */
+
+	      usleep (10000);
+	    }
+
+	  /* Since we vforked, breakpoints were removed in the parent
+	     too.  Put them back.  */
+	  reattach_breakpoints (parent_pid);
+	}
     }
   else
     {
       char child_pid_spelling[40];
 
       /* Needed to keep the breakpoint lists in sync.  */
-      detach_breakpoints (child_pid);
+      if (! has_vforked)
+	detach_breakpoints (child_pid);
 
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
@@ -265,7 +352,28 @@ child_follow_fork (int follow_child)
 			"Attaching after fork to child process %d.\n",
 			child_pid);
 
-      target_detach (NULL, 0);
+      /* 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.  */
+
+      if (has_vforked)
+	linux_parent_pid = parent_pid;
+      else
+	target_detach (NULL, 0);
 
       inferior_ptid = pid_to_ptid (child_pid);
       push_target (&child_ops);
@@ -287,7 +395,7 @@ linux_handle_extended_wait (int pid, int
     internal_error (__FILE__, __LINE__,
 		    "unexpected clone event");
 
-  if (event == PTRACE_EVENT_FORK)
+  if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
     {
       unsigned long new_pid;
       int ret;
@@ -315,11 +423,29 @@ linux_handle_extended_wait (int pid, int
 			    "wait returned unexpected status 0x%x", status);
 	}
 
-      ourstatus->kind = TARGET_WAITKIND_FORKED;
+      ourstatus->kind = (event == PTRACE_EVENT_FORK)
+	? TARGET_WAITKIND_FORKED : TARGET_WAITKIND_VFORKED;
       ourstatus->value.related_pid = new_pid;
       return inferior_ptid;
     }
 
+  if (event == PTRACE_EVENT_EXEC)
+    {
+      ourstatus->kind = TARGET_WAITKIND_EXECD;
+      ourstatus->value.execd_pathname
+	= xstrdup (child_pid_to_exec_file (pid));
+
+      if (linux_parent_pid)
+	{
+	  detach_breakpoints (linux_parent_pid);
+	  ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
+
+	  linux_parent_pid = 0;
+	}
+
+      return inferior_ptid;
+    }
+
   internal_error (__FILE__, __LINE__,
 		  "unknown ptrace event %d", event);
 }
@@ -337,19 +463,19 @@ child_insert_fork_catchpoint (int pid)
 int
 child_insert_vfork_catchpoint (int pid)
 {
-  if (linux_supports_tracefork ())
-    error ("Vfork catchpoints have not been implemented yet.");
-  else
+  if (!linux_supports_tracefork ())
     error ("Your system does not support vfork catchpoints.");
+
+  return 0;
 }
 
 int
 child_insert_exec_catchpoint (int pid)
 {
-  if (linux_supports_tracefork ())
-    error ("Exec catchpoints have not been implemented yet.");
-  else
+  if (!linux_supports_tracefork ())
     error ("Your system does not support exec catchpoints.");
+
+  return 0;
 }
 
 void
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.117
diff -u -p -r1.117 NEWS
--- NEWS	16 Aug 2003 18:38:46 -0000	1.117
+++ NEWS	17 Aug 2003 20:16:17 -0000
@@ -11,6 +11,12 @@ tested, nor mentioned in the NEWS file.
 
 *** Changes in GDB 6.0:
 
+* GNU/Linux support for fork, vfork, and exec.
+
+The "catch fork", "catch exec", "catch vfork", and "set follow-fork-mode"
+commands are now implemented for GNU/Linux.  They require a 2.5.x or later
+kernel.
+
 * GDB supports logging output to a file
 
 There are two new commands, "set logging" and "show logging", which can be


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [commit] Last major piece of fork tracing - vfork/exec
@ 2003-08-22 15:53 Michael Elizabeth Chastain
  2003-08-22 18:40 ` Andrew Cagney
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Elizabeth Chastain @ 2003-08-22 15:53 UTC (permalink / raw)
  To: ac131313, drow; +Cc: gdb-patches

I hate to cause trouble here.  We're all on edge with the release
coming up (and this is also end-of-quarter for the red hat people).
But I have to speak up.

The release is already being held up for the gdb.c++ -> gdb.cp
renaming.  The one-week comment period for that change ends this
afternoon.  Then I can commit this change to gdb HEAD.  Then it
needs a shakedown period in gdb HEAD.  Then I can commit the
change to gdb gdb_6_0-branch, and it will need a shakedown period
there as well.

Andrew, I'm frankly amazed that you decided this feature was
release critical, but that's okay.  My role is to get it into
the branch expeditiously.

Also I'm not saying "as long as we have one dependency it's okay
to have two".  Dependencies are expensive, mmmkay.  I'm just
saying that gdb 6.0 already has this gdb.cp dependency, so it's
not all Daniel's fault that the release is slipping.

Michael C


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [commit] Last major piece of fork tracing - vfork/exec
@ 2003-08-22 19:36 Michael Elizabeth Chastain
  2003-08-22 22:07 ` Andrew Cagney
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Elizabeth Chastain @ 2003-08-22 19:36 UTC (permalink / raw)
  To: ac131313; +Cc: drow, gdb-patches

> The release isn't been held up for the gdb.cp rename, it happened to 
> slip nicely into the schedule.  If it's not done by Sunday, I can easily 
> do it myself.

I am planning to do it in HEAD this evening.  I really think that
Sunday is premature for doing it on the branch.  :(

However, if you want to give me an H-Hour, I can do the grunt work
on the branch at that time.  Say, 4:00 PM on Sunday UTC?

Michael C


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [commit] Last major piece of fork tracing - vfork/exec
@ 2003-08-25  1:19 Michael Elizabeth Chastain
  2003-08-25 15:06 ` Andrew Cagney
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Elizabeth Chastain @ 2003-08-25  1:19 UTC (permalink / raw)
  To: ac131313; +Cc: gdb-patches

ac> 00:00 Monday GMT.  Which is 7ish sunday new york time.

Argh!  I dropped the time zone and was thinking '00:00 local time'
not '00:00 GMT', so I missed the deadline.  I'm working on it now.

Michael C


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2003-08-25 15:06 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-17 20:19 [commit] Last major piece of fork tracing - vfork/exec Daniel Jacobowitz
2003-08-18 15:46 ` Andrew Cagney
2003-08-22 15:32   ` Andrew Cagney
2003-08-22 21:20     ` Daniel Jacobowitz
2003-08-22 15:53 Michael Elizabeth Chastain
2003-08-22 18:40 ` Andrew Cagney
2003-08-22 19:36 Michael Elizabeth Chastain
2003-08-22 22:07 ` Andrew Cagney
2003-08-25  1:19 Michael Elizabeth Chastain
2003-08-25 15:06 ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox