Blame SOURCES/gdb-rhbz1210889-thread-call-clone.patch

7b26da
  NOTE: This patch has been forwardported from RHEL-6.7.
7b26da
7b26da
  From: Pedro Alves <palves@redhat.com>
7b26da
  Date: Fri, 20 Feb 2015 19:10:08 +0000
7b26da
  Subject: [PATCH] PR18006: internal error if threaded program calls
7b26da
   clone(CLONE_VM)
7b26da
7b26da
  On GNU/Linux, if a pthreaded program has a thread call clone(CLONE_VM)
7b26da
  directly, and then that clone LWP hits a debug event (breakpoint,
7b26da
  etc.) GDB internal errors.  Threaded programs shouldn't really be
7b26da
  calling clone directly, but GDB shouldn't crash either.
7b26da
7b26da
  The crash looks like this:
7b26da
7b26da
  (gdb) break clone_fn
7b26da
   Breakpoint 1 at 0x4007d8: file clone-thread_db.c, line 35.
7b26da
   (gdb) r
7b26da
   ...
7b26da
   [Thread debugging using libthread_db enabled]
7b26da
   ...
7b26da
   [New Thread 0x7ffff7fc2700 (LWP 3886)]
7b26da
   ../../gdb/linux-thread-db.c:437: internal-error: thread_get_info_callback: Assertion `inout->thread_info != NULL' failed.
7b26da
   A problem internal to GDB has been detected,
7b26da
   further debugging may prove unreliable.
7b26da
7b26da
  The problem is that 'clone' ends up clearing the parent thread's tid
7b26da
  field in glibc's thread data structure.  For x86_64, the glibc code in
7b26da
  question is here:
7b26da
7b26da
    sysdeps/unix/sysv/linux/x86_64/clone.S:
7b26da
7b26da
     ...
7b26da
	    testq   $CLONE_THREAD, %rdi
7b26da
	    jne     1f
7b26da
	    testq   $CLONE_VM, %rdi
7b26da
	    movl    $-1, %eax            <----
7b26da
	    jne     2f
7b26da
	    movl    $SYS_ify(getpid), %eax
7b26da
	    syscall
7b26da
    2:      movl    %eax, %fs:PID
7b26da
	    movl    %eax, %fs:TID        <----
7b26da
    1:
7b26da
7b26da
  When GDB refreshes the thread list out of libthread_db, it finds a
7b26da
  thread with LWP with pid -1 (the clone's parent), which naturally
7b26da
  isn't yet on the thread list.  GDB then tries to attach to that bogus
7b26da
  LWP id, that fails, and then GDB gets confused.
7b26da
7b26da
  The fix is to detect the bad PID early.
7b26da
7b26da
  Tested on x86-64 Fedora 20.  GDBserver doesn't need any fix.
7b26da
7b26da
  gdb/ChangeLog:
7b26da
  2015-02-20  Pedro Alves  <palves@redhat.com>
7b26da
7b26da
	  PR threads/18006
7b26da
	  * linux-thread-db.c (thread_get_info_callback): Return early if
7b26da
	  the thread's lwp id is -1.
7b26da
	  (check_event): On TD_DEATH, if the thread is not on the thread
7b26da
	  list, warn instead of erroring out.
7b26da
7b26da
  gdb/testsuite/ChangeLog:
7b26da
  2015-02-20  Pedro Alves  <palves@redhat.com>
7b26da
7b26da
	  PR threads/18006
7b26da
	  * gdb.threads/clone-thread_db.c: New file.
7b26da
	  * gdb.threads/clone-thread_db.exp: New file.
7b26da
---
7b26da
 gdb/linux-thread-db.c                         | 14 +++--
7b26da
 gdb/testsuite/gdb.threads/clone-thread_db.c   | 73 +++++++++++++++++++++++++++
7b26da
 gdb/testsuite/gdb.threads/clone-thread_db.exp | 44 ++++++++++++++++
7b26da
 3 files changed, 128 insertions(+), 3 deletions(-)
7b26da
 create mode 100644 gdb/testsuite/gdb.threads/clone-thread_db.c
7b26da
 create mode 100644 gdb/testsuite/gdb.threads/clone-thread_db.exp
7b26da
7b26da
Index: gdb-7.6.1/gdb/linux-thread-db.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/linux-thread-db.c
7b26da
+++ gdb-7.6.1/gdb/linux-thread-db.c
7b26da
@@ -422,6 +422,14 @@ thread_get_info_callback (const td_thrha
7b26da
     error (_("thread_get_info_callback: cannot get thread info: %s"),
7b26da
 	   thread_db_err_str (err));
7b26da
 
7b26da
+  if (ti.ti_lid == -1)
7b26da
+    {
7b26da
+      /* We'll get this if a threaded program has a thread call clone
7b26da
+	 with CLONE_VM.  `clone' sets the pthread LID of the new LWP
7b26da
+	 to -1, which ends up clearing the parent thread's LID.  */
7b26da
+      return 0;
7b26da
+    }
7b26da
+
7b26da
   /* Fill the cache.  */
7b26da
   thread_ptid = ptid_build (info->pid, ti.ti_lid, 0);
7b26da
   inout->thread_info = find_thread_ptid (thread_ptid);
7b26da
@@ -1454,9 +1462,9 @@ check_event (ptid_t ptid)
7b26da
 	case TD_DEATH:
7b26da
 
7b26da
 	  if (!in_thread_list (ptid))
7b26da
-	    error (_("Spurious thread death event."));
7b26da
-
7b26da
-	  detach_thread (ptid);
7b26da
+	    warning (_("Spurious thread death event."));
7b26da
+	  else
7b26da
+	    detach_thread (ptid);
7b26da
 
7b26da
 	  break;
7b26da
 
7b26da
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.c
7b26da
===================================================================
7b26da
--- /dev/null
7b26da
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.c
7b26da
@@ -0,0 +1,75 @@
7b26da
+/* This testcase is part of GDB, the GNU debugger.
7b26da
+
7b26da
+   Copyright 2015 Free Software Foundation, Inc.
7b26da
+
7b26da
+   This program is free software; you can redistribute it and/or modify
7b26da
+   it under the terms of the GNU General Public License as published by
7b26da
+   the Free Software Foundation; either version 3 of the License, or
7b26da
+   (at your option) any later version.
7b26da
+
7b26da
+   This program is distributed in the hope that it will be useful,
7b26da
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
7b26da
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7b26da
+   GNU General Public License for more details.
7b26da
+
7b26da
+   You should have received a copy of the GNU General Public License
7b26da
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
7b26da
+
7b26da
+   Test that GDB doesn't lose an event for a thread it didn't know
7b26da
+   about, until an event is reported for it.  */
7b26da
+
7b26da
+#define _GNU_SOURCE
7b26da
+#include <sched.h>
7b26da
+#include <assert.h>
7b26da
+#include <stdlib.h>
7b26da
+#include <sys/types.h>
7b26da
+#include <sys/wait.h>
7b26da
+#include <unistd.h>
7b26da
+#include <pthread.h>
7b26da
+
7b26da
+#define STACK_SIZE 0x1000
7b26da
+
7b26da
+int clone_pid;
7b26da
+
7b26da
+static int
7b26da
+clone_fn (void *unused)
7b26da
+{
7b26da
+  return 0;
7b26da
+}
7b26da
+
7b26da
+void *
7b26da
+thread_fn (void *arg)
7b26da
+{
7b26da
+  unsigned char *stack;
7b26da
+  int res;
7b26da
+
7b26da
+  stack = malloc (STACK_SIZE);
7b26da
+  assert (stack != NULL);
7b26da
+
7b26da
+#ifdef __ia64__
7b26da
+  clone_pid = __clone2 (clone_fn, stack, STACK_SIZE, CLONE_VM, NULL);
7b26da
+#else
7b26da
+  clone_pid = clone (clone_fn, stack + STACK_SIZE, CLONE_VM, NULL);
7b26da
+#endif
7b26da
+
7b26da
+  assert (clone_pid > 0);
7b26da
+
7b26da
+  /* Wait for child.  */
7b26da
+  res = waitpid (clone_pid, NULL, __WCLONE);
7b26da
+  assert (res != -1);
7b26da
+
7b26da
+  return NULL;
7b26da
+}
7b26da
+
7b26da
+int
7b26da
+main (int argc, char **argv)
7b26da
+{
7b26da
+  pthread_t child;
7b26da
+
7b26da
+  alarm (300);
7b26da
+
7b26da
+  pthread_create (&child, NULL, thread_fn, NULL);
7b26da
+  pthread_join (child, NULL);
7b26da
+
7b26da
+  return 0;
7b26da
+}
7b26da
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.exp
7b26da
===================================================================
7b26da
--- /dev/null
7b26da
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.exp
7b26da
@@ -0,0 +1,44 @@
7b26da
+# This testcase is part of GDB, the GNU debugger.
7b26da
+
7b26da
+# Copyright 2015 Free Software Foundation, Inc.
7b26da
+
7b26da
+# This program is free software; you can redistribute it and/or modify
7b26da
+# it under the terms of the GNU General Public License as published by
7b26da
+# the Free Software Foundation; either version 3 of the License, or
7b26da
+# (at your option) any later version.
7b26da
+#
7b26da
+# This program is distributed in the hope that it will be useful,
7b26da
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
7b26da
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7b26da
+# GNU General Public License for more details.
7b26da
+#
7b26da
+# You should have received a copy of the GNU General Public License
7b26da
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
7b26da
+
7b26da
+# This only works on targets with the Linux kernel.
7b26da
+if ![istarget *-*-linux*] {
7b26da
+    return
7b26da
+}
7b26da
+
7b26da
+set testfile "clone-thread_db"
7b26da
+set srcfile ${testfile}.c
7b26da
+set binfile ${objdir}/${subdir}/${testfile}
7b26da
+
7b26da
+if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
7b26da
+    untested $testfile.exp
7b26da
+    return -1
7b26da
+}
7b26da
+
7b26da
+gdb_start
7b26da
+gdb_reinitialize_dir $srcdir/$subdir
7b26da
+gdb_load ${binfile}
7b26da
+
7b26da
+if ![runto_main] {
7b26da
+    untested "could not run to main"
7b26da
+    return -1
7b26da
+}
7b26da
+
7b26da
+gdb_test "break clone_fn" "Breakpoint.*at.*file.*$srcfile.*line.*"
7b26da
+gdb_test "continue" "clone_fn .* at .*" "continue to clone_fn"
7b26da
+
7b26da
+gdb_test "continue" "exited normally.*" "continue to end"