patches/gdb/6.3/730-debian_gdb-fix-tracefork-check.patch
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Jul 30 21:09:12 2007 +0000 (2007-07-30)
changeset 306 1984d7bcea28
permissions -rw-r--r--
Small typo fix.
yann@96
     1
Status: submitted for comments
yann@96
     2
yann@96
     3
2004-11-12  Daniel Jacobowitz  <dan@debian.org>
yann@96
     4
yann@96
     5
	* linux-nat.c (my_waitpid): New function.
yann@96
     6
	(linux_test_for_tracefork): Make more robust and verbose.  Take
yann@96
     7
	an ORIGINAL_PID argument and test for PTRACE_SETOPTIONS first.
yann@96
     8
	(linux_supports_tracefork, linux_supports_tracevforkdone): Take a PID
yann@96
     9
	argument.  Update calls to linux_test_for_tracefork.
yann@96
    10
	(linux_enable_event_reporting, child_follow_fork)
yann@96
    11
	(child_insert_fork_catchpoint, child_insert_vfork_catchpoint)
yann@96
    12
	(child_insert_exec_catchpoint): Update calls to
yann@96
    13
	linux_supports_tracefork and linux_supports_tracevforkdone.
yann@96
    14
yann@96
    15
Index: gdb-6.3/gdb/linux-nat.c
yann@96
    16
===================================================================
yann@96
    17
--- gdb-6.3.orig/gdb/linux-nat.c	2004-10-08 16:29:47.000000000 -0400
yann@96
    18
+++ gdb-6.3/gdb/linux-nat.c	2004-11-13 16:41:51.368720845 -0500
yann@96
    19
@@ -150,18 +150,47 @@ linux_tracefork_child (void)
yann@96
    20
   exit (0);
yann@96
    21
 }
yann@96
    22
 
yann@96
    23
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.  We
yann@96
    24
+/* Wrapper function for waitpid which handles EINTR.  */
yann@96
    25
+
yann@96
    26
+static int
yann@96
    27
+my_waitpid (int pid, int *status, int flags)
yann@96
    28
+{
yann@96
    29
+  int ret;
yann@96
    30
+  do
yann@96
    31
+    {
yann@96
    32
+      ret = waitpid (pid, status, flags);
yann@96
    33
+    }
yann@96
    34
+  while (ret == -1 && errno == EINTR);
yann@96
    35
+
yann@96
    36
+  return ret;
yann@96
    37
+}
yann@96
    38
+
yann@96
    39
+/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
yann@96
    40
+
yann@96
    41
+   First, we try to enable fork tracing on ORIGINAL_PID.  If this fails,
yann@96
    42
+   we know that the feature is not available.  This may change the tracing
yann@96
    43
+   options for ORIGINAL_PID, but we'll be setting them shortly anyway.
yann@96
    44
+
yann@96
    45
+   However, if it succeeds, we don't know for sure that the feature is
yann@96
    46
+   available; old versions of PTRACE_SETOPTIONS ignored unknown options.  We
yann@96
    47
    create a child process, attach to it, use PTRACE_SETOPTIONS to enable
yann@96
    48
-   fork tracing, and let it fork.  If the process exits, we assume that
yann@96
    49
-   we can't use TRACEFORK; if we get the fork notification, and we can
yann@96
    50
-   extract the new child's PID, then we assume that we can.  */
yann@96
    51
+   fork tracing, and let it fork.  If the process exits, we assume that we
yann@96
    52
+   can't use TRACEFORK; if we get the fork notification, and we can extract
yann@96
    53
+   the new child's PID, then we assume that we can.  */
yann@96
    54
 
yann@96
    55
 static void
yann@96
    56
-linux_test_for_tracefork (void)
yann@96
    57
+linux_test_for_tracefork (int original_pid)
yann@96
    58
 {
yann@96
    59
   int child_pid, ret, status;
yann@96
    60
   long second_pid;
yann@96
    61
 
yann@96
    62
+  linux_supports_tracefork_flag = 0;
yann@96
    63
+  linux_supports_tracevforkdone_flag = 0;
yann@96
    64
+
yann@96
    65
+  ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
yann@96
    66
+  if (ret != 0)
yann@96
    67
+    return;
yann@96
    68
+
yann@96
    69
   child_pid = fork ();
yann@96
    70
   if (child_pid == -1)
yann@96
    71
     perror_with_name ("linux_test_for_tracefork: fork");
yann@96
    72
@@ -169,7 +198,7 @@ linux_test_for_tracefork (void)
yann@96
    73
   if (child_pid == 0)
yann@96
    74
     linux_tracefork_child ();
yann@96
    75
 
yann@96
    76
-  ret = waitpid (child_pid, &status, 0);
yann@96
    77
+  ret = my_waitpid (child_pid, &status, 0);
yann@96
    78
   if (ret == -1)
yann@96
    79
     perror_with_name ("linux_test_for_tracefork: waitpid");
yann@96
    80
   else if (ret != child_pid)
yann@96
    81
@@ -177,13 +206,23 @@ linux_test_for_tracefork (void)
yann@96
    82
   if (! WIFSTOPPED (status))
yann@96
    83
     error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
yann@96
    84
 
yann@96
    85
-  linux_supports_tracefork_flag = 0;
yann@96
    86
-
yann@96
    87
   ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
yann@96
    88
   if (ret != 0)
yann@96
    89
     {
yann@96
    90
-      ptrace (PTRACE_KILL, child_pid, 0, 0);
yann@96
    91
-      waitpid (child_pid, &status, 0);
yann@96
    92
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
yann@96
    93
+      if (ret != 0)
yann@96
    94
+	{
yann@96
    95
+	  warning ("linux_test_for_tracefork: failed to kill child");
yann@96
    96
+	  return;
yann@96
    97
+	}
yann@96
    98
+
yann@96
    99
+      ret = my_waitpid (child_pid, &status, 0);
yann@96
   100
+      if (ret != child_pid)
yann@96
   101
+	warning ("linux_test_for_tracefork: failed to wait for killed child");
yann@96
   102
+      else if (!WIFSIGNALED (status))
yann@96
   103
+	warning ("linux_test_for_tracefork: unexpected wait status 0x%x from "
yann@96
   104
+		 "killed child", status);
yann@96
   105
+
yann@96
   106
       return;
yann@96
   107
     }
yann@96
   108
 
yann@96
   109
@@ -192,8 +231,12 @@ linux_test_for_tracefork (void)
yann@96
   110
 		PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
yann@96
   111
   linux_supports_tracevforkdone_flag = (ret == 0);
yann@96
   112
 
yann@96
   113
-  ptrace (PTRACE_CONT, child_pid, 0, 0);
yann@96
   114
-  ret = waitpid (child_pid, &status, 0);
yann@96
   115
+  ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
yann@96
   116
+  if (ret != 0)
yann@96
   117
+    warning ("linux_test_for_tracefork: failed to resume child");
yann@96
   118
+
yann@96
   119
+  ret = my_waitpid (child_pid, &status, 0);
yann@96
   120
+
yann@96
   121
   if (ret == child_pid && WIFSTOPPED (status)
yann@96
   122
       && status >> 16 == PTRACE_EVENT_FORK)
yann@96
   123
     {
yann@96
   124
@@ -204,34 +247,38 @@ linux_test_for_tracefork (void)
yann@96
   125
 	  int second_status;
yann@96
   126
 
yann@96
   127
 	  linux_supports_tracefork_flag = 1;
yann@96
   128
-	  waitpid (second_pid, &second_status, 0);
yann@96
   129
-	  ptrace (PTRACE_DETACH, second_pid, 0, 0);
yann@96
   130
+	  my_waitpid (second_pid, &second_status, 0);
yann@96
   131
+	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
yann@96
   132
+	  if (ret != 0)
yann@96
   133
+	    warning ("linux_test_for_tracefork: failed to kill second child");
yann@96
   134
 	}
yann@96
   135
     }
yann@96
   136
+  else
yann@96
   137
+    warning ("linux_test_for_tracefork: unexpected result from waitpid "
yann@96
   138
+	     "(%d, status 0x%x)", ret, status);
yann@96
   139
 
yann@96
   140
-  if (WIFSTOPPED (status))
yann@96
   141
-    {
yann@96
   142
-      ptrace (PTRACE_DETACH, child_pid, 0, 0);
yann@96
   143
-      waitpid (child_pid, &status, 0);
yann@96
   144
-    }
yann@96
   145
+  ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
yann@96
   146
+  if (ret != 0)
yann@96
   147
+    warning ("linux_test_for_tracefork: failed to kill child");
yann@96
   148
+  my_waitpid (child_pid, &status, 0);
yann@96
   149
 }
yann@96
   150
 
yann@96
   151
 /* Return non-zero iff we have tracefork functionality available.
yann@96
   152
    This function also sets linux_supports_tracefork_flag.  */
yann@96
   153
 
yann@96
   154
 static int
yann@96
   155
-linux_supports_tracefork (void)
yann@96
   156
+linux_supports_tracefork (int pid)
yann@96
   157
 {
yann@96
   158
   if (linux_supports_tracefork_flag == -1)
yann@96
   159
-    linux_test_for_tracefork ();
yann@96
   160
+    linux_test_for_tracefork (pid);
yann@96
   161
   return linux_supports_tracefork_flag;
yann@96
   162
 }
yann@96
   163
 
yann@96
   164
 static int
yann@96
   165
-linux_supports_tracevforkdone (void)
yann@96
   166
+linux_supports_tracevforkdone (int pid)
yann@96
   167
 {
yann@96
   168
   if (linux_supports_tracefork_flag == -1)
yann@96
   169
-    linux_test_for_tracefork ();
yann@96
   170
+    linux_test_for_tracefork (pid);
yann@96
   171
   return linux_supports_tracevforkdone_flag;
yann@96
   172
 }
yann@96
   173
 
yann@96
   174
@@ -242,12 +289,12 @@ linux_enable_event_reporting (ptid_t pti
yann@96
   175
   int pid = ptid_get_pid (ptid);
yann@96
   176
   int options;
yann@96
   177
 
yann@96
   178
-  if (! linux_supports_tracefork ())
yann@96
   179
+  if (! linux_supports_tracefork (pid))
yann@96
   180
     return;
yann@96
   181
 
yann@96
   182
   options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
yann@96
   183
     | PTRACE_O_TRACECLONE;
yann@96
   184
-  if (linux_supports_tracevforkdone ())
yann@96
   185
+  if (linux_supports_tracevforkdone (pid))
yann@96
   186
     options |= PTRACE_O_TRACEVFORKDONE;
yann@96
   187
 
yann@96
   188
   /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
yann@96
   189
@@ -308,7 +355,8 @@ child_follow_fork (int follow_child)
yann@96
   190
 
yann@96
   191
       if (has_vforked)
yann@96
   192
 	{
yann@96
   193
-	  if (linux_supports_tracevforkdone ())
yann@96
   194
+	  gdb_assert (linux_supports_tracefork_flag >= 0);
yann@96
   195
+	  if (linux_supports_tracevforkdone (0))
yann@96
   196
 	    {
yann@96
   197
 	      int status;
yann@96
   198
 
yann@96
   199
@@ -476,7 +524,7 @@ linux_handle_extended_wait (int pid, int
yann@96
   200
 int
yann@96
   201
 child_insert_fork_catchpoint (int pid)
yann@96
   202
 {
yann@96
   203
-  if (! linux_supports_tracefork ())
yann@96
   204
+  if (! linux_supports_tracefork (pid))
yann@96
   205
     error ("Your system does not support fork catchpoints.");
yann@96
   206
 
yann@96
   207
   return 0;
yann@96
   208
@@ -485,7 +533,7 @@ child_insert_fork_catchpoint (int pid)
yann@96
   209
 int
yann@96
   210
 child_insert_vfork_catchpoint (int pid)
yann@96
   211
 {
yann@96
   212
-  if (!linux_supports_tracefork ())
yann@96
   213
+  if (!linux_supports_tracefork (pid))
yann@96
   214
     error ("Your system does not support vfork catchpoints.");
yann@96
   215
 
yann@96
   216
   return 0;
yann@96
   217
@@ -494,7 +542,7 @@ child_insert_vfork_catchpoint (int pid)
yann@96
   218
 int
yann@96
   219
 child_insert_exec_catchpoint (int pid)
yann@96
   220
 {
yann@96
   221
-  if (!linux_supports_tracefork ())
yann@96
   222
+  if (!linux_supports_tracefork (pid))
yann@96
   223
     error ("Your system does not support exec catchpoints.");
yann@96
   224
 
yann@96
   225
   return 0;