Blame SOURCES/gdb-rhbz1210135-internal-error-linux_nat_post_attach_wait.patch

2c2fa1
  NOTE: This patch has been forwardported to RHEL-7.2.  It is originally
2c2fa1
  from RHEL-6.7.
2c2fa1
2c2fa1
  Message-ID: <54E37CE7.50703@redhat.com>
2c2fa1
  Date: Tue, 17 Feb 2015 17:39:51 +0000
2c2fa1
  From: Pedro Alves <palves@redhat.com>
2c2fa1
  To: Sergio Durigan Junior <sergiodj@redhat.com>
2c2fa1
  Subject: [debug-list] [PATCH] RH BZ #1162264 - gdb/linux-nat.c:1411:
2c2fa1
   internal-error:,
2c2fa1
   linux_nat_post_attach_wait: Assertion `pid == new_pid' failed.
2c2fa1
2c2fa1
  Hi.
2c2fa1
2c2fa1
  Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1162264
2c2fa1
2c2fa1
  So I spend a few more hours today trying to reproduce the
2c2fa1
  EACCES, to no avail.  Also, unfortunately, none of the attach
2c2fa1
  bugs exposed by attach-many-short-lived-threads.exp test
2c2fa1
  can explain this.
2c2fa1
2c2fa1
  It seems to be that really the best we can do is cope with
2c2fa1
  the error, like in the patch below.
2c2fa1
2c2fa1
  Note that the backtrace at
2c2fa1
2c2fa1
   https://bugzilla.redhat.com/show_bug.cgi?id=1162264#c3 :
2c2fa1
2c2fa1
  shows that this triggers for the main thread already:
2c2fa1
2c2fa1
  ...
2c2fa1
  #6  0x000000000044fd2e in linux_nat_post_attach_wait (ptid=..., first=1, cloned=0x1d84368,
2c2fa1
  ...
2c2fa1
2c2fa1
  (note "first=1").
2c2fa1
2c2fa1
  For upstream, I think linux_nat_attach should be adjusted to work
2c2fa1
  like gdbserver -- that is, leave the initial waitpid to the main
2c2fa1
  wait code, like all other events, instead of synchronously
2c2fa1
  doing waitpid(PID).  That'll get rid of linux_nat_post_attach_wait
2c2fa1
  altogether.  But that's too invasive for a bug fix.
2c2fa1
2c2fa1
  >From 072c61aeb9adc64e1eb45c120061b85fbf6f4d25 Mon Sep 17 00:00:00 2001
2c2fa1
  From: Pedro Alves <palves@redhat.com>
2c2fa1
  Date: Tue, 17 Feb 2015 17:11:05 +0000
2c2fa1
  Subject: [PATCH] RH BZ #1162264 - gdb/linux-nat.c:1411: internal-error:
2c2fa1
   linux_nat_post_attach_wait: Assertion `pid == new_pid' failed.
2c2fa1
2c2fa1
  According to BZ #1162264, it can happen that we manage to attach to a
2c2fa1
  process, but then waitpid on it fails with EACCES.  That's unexpected,
2c2fa1
  and gdb hits an assertion.  But given this is an error that is out of
2c2fa1
  our control, we should handle it gracefully.  I wasn't able to
2c2fa1
  reproduce the EACCES, but hacking in the error, like:
2c2fa1
2c2fa1
  |  --- a/gdb/linux-nat.c
2c2fa1
  |  +++ b/gdb/linux-nat.c
2c2fa1
  |  @@ -1409,7 +1409,7 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
2c2fa1
  | 	   *cloned = 1;
2c2fa1
  | 	 }
2c2fa1
  | 
2c2fa1
  |  -  if (new_pid != pid)
2c2fa1
  |  +  if (new_pid != pid || 1)
2c2fa1
  | 	 {
2c2fa1
  | 	   int saved_errno = errno;
2c2fa1
  | 
2c2fa1
  |  @@ -1423,6 +1423,7 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
2c2fa1
  | 	   ptrace (PTRACE_DETACH, pid, 0, 0);
2c2fa1
  | 
2c2fa1
  | 	   errno = saved_errno;
2c2fa1
  |  +      errno = EACCES;
2c2fa1
  | 	   perror_with_name (_("waitpid"));
2c2fa1
  | 	 }
2c2fa1
2c2fa1
  ... I could confirm that the error handling works properly.  On the
2c2fa1
  EACCES case, we get:
2c2fa1
2c2fa1
   (gdb) attach 1202
2c2fa1
   Attaching to process 1202
2c2fa1
   Unable to attach: waitpid: Permission denied.
2c2fa1
   (gdb) info inferiors
2c2fa1
     Num  Description       Executable
2c2fa1
   * 1    <null>
2c2fa1
   (gdb)
2c2fa1
2c2fa1
  No test because the conditions that lead to the waitpid error are
2c2fa1
  unknown.
2c2fa1
2c2fa1
  gdb/ChangeLog:
2c2fa1
  2015-02-17  Pedro Alves  <palves@redhat.com>
2c2fa1
2c2fa1
	  * linux-nat.c: Include "exceptions.h".
2c2fa1
	  (linux_nat_post_attach_wait): If waitpid returns an excepted
2c2fa1
	  result, detach and error out instead of asserting.
2c2fa1
	  (linux_nat_attach): Wrap linux_nat_post_attach_wait in TRY_CATCH.
2c2fa1
	  Mourn inferior and rethrow in case of error while waiting for the
2c2fa1
	  initial stop.
2c2fa1
---
2c2fa1
 gdb/linux-nat.c | 34 +++++++++++++++++++++++++++++++---
2c2fa1
 1 file changed, 31 insertions(+), 3 deletions(-)
2c2fa1
2c2fa1
Index: gdb-7.6.1/gdb/linux-nat.c
2c2fa1
===================================================================
2c2fa1
--- gdb-7.6.1.orig/gdb/linux-nat.c
2c2fa1
+++ gdb-7.6.1/gdb/linux-nat.c
2c2fa1
@@ -1397,7 +1397,22 @@ linux_nat_post_attach_wait (ptid_t ptid,
2c2fa1
       *cloned = 1;
2c2fa1
     }
2c2fa1
 
2c2fa1
-  gdb_assert (pid == new_pid);
2c2fa1
+  if (new_pid != pid)
2c2fa1
+    {
2c2fa1
+      int saved_errno = errno;
2c2fa1
+
2c2fa1
+      /* Unexpected waitpid result.  EACCES has been observed on RHEL
2c2fa1
+	 6.5 (RH BZ #1162264).  This is most likely a kernel bug, thus
2c2fa1
+	 out of our control, so treat it as invalid input.  The LWP's
2c2fa1
+	 state is indeterminate at this point, so best we can do is
2c2fa1
+	 error out, otherwise we'd probably end up wedged later on.
2c2fa1
+
2c2fa1
+	 In case we're still attached.  */
2c2fa1
+      ptrace (PTRACE_DETACH, pid, 0, 0);
2c2fa1
+
2c2fa1
+      errno = saved_errno;
2c2fa1
+      perror_with_name (_("waitpid"));
2c2fa1
+    }
2c2fa1
 
2c2fa1
   if (!WIFSTOPPED (status))
2c2fa1
     {
2c2fa1
@@ -1621,7 +1636,7 @@ static void
2c2fa1
 linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
2c2fa1
 {
2c2fa1
   struct lwp_info *lp;
2c2fa1
-  int status;
2c2fa1
+  int status = 0;
2c2fa1
   ptid_t ptid;
2c2fa1
   volatile struct gdb_exception ex;
2c2fa1
 
2c2fa1
@@ -1659,8 +1674,19 @@ linux_nat_attach (struct target_ops *ops
2c2fa1
   /* Add the initial process as the first LWP to the list.  */
2c2fa1
   lp = add_initial_lwp (ptid);
2c2fa1
 
2c2fa1
-  status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned,
2c2fa1
-				       &lp->signalled);
2c2fa1
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
2c2fa1
+    {
2c2fa1
+      status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned,
2c2fa1
+					   &lp->signalled);
2c2fa1
+    }
2c2fa1
+  if (ex.reason < 0)
2c2fa1
+    {
2c2fa1
+      target_terminal_ours ();
2c2fa1
+      target_mourn_inferior ();
2c2fa1
+
2c2fa1
+      error (_("Unable to attach: %s"), ex.message);
2c2fa1
+    }
2c2fa1
+
2c2fa1
   if (!WIFSTOPPED (status))
2c2fa1
     {
2c2fa1
       if (WIFEXITED (status))