Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Jan Kratochvil <lace@jankratochvil.net>
To: gdb-patches@sourceware.org
Subject: RFC: Fix crash on i386 (%gs-)threaded programs using execve(2)
Date: Wed, 14 Jun 2006 10:55:00 -0000	[thread overview]
Message-ID: <20060614105510.GA12067@host0.dyn.jankratochvil.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 1984 bytes --]

Hi all,

right now gdb(1) crashes on execve(2) executed by any -lpthread i386 process
on recent %gs based TLS glibc.

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=182116

(new test case "gdb.threads/thread-lost")
Currently:

# gcc -o ./testsuite/gdb.threads/thread-lost ./testsuite/gdb.threads/thread-lost.c -Wall -lpthread -ggdb3
# ./gdb -nx ./testsuite/gdb.threads/thread-lost
GNU gdb 6.5.50.20060614-cvs
...
(gdb) run
Starting program: /home/lace/redhat/src/gdb/testsuite/gdb.threads/thread-lost
[Thread debugging using libthread_db enabled]
[New Thread -1208801600 (LWP 17677)]
Cannot find user-level thread for LWP 17677: generic error
(gdb) bt
Cannot fetch general-purpose registers for thread -1208801600: generic error

With the patch:

(gdb) run
Starting program: /home/lace/redhat/src/gdb/testsuite/gdb.threads/thread-lost
[Thread debugging using libthread_db enabled]
[New Thread -1208301888 (LWP 18818)]
warning: Original threaded process got lost, dropping threads
EXECUTED
Program exited normally.


It is only a heuristic as execve(2) destroys %gs and gdb(1) fails to find the
no longer existing threads through TLS. Patch will warn and turn off the gdb(1)
threads support if it finds out %gs==0.

On i386 with %gs based TLS NPTLS gdb calls glibc td_ta_map_lwp2thr() which
calls ta_howto_reg_thread_area() (case ta_howto_reg_thread_area).
After execve(2) it retrieves %gs as 0 and fails to ps_get_thread_area()
as its idx must be 6 (glibc TLS descriptor) - value of the first/glibc Linux
kernel GDT_ENTRY_TLS_MIN.
It is now workarounded as to drop threading support if %gs==0.

Do you have an idea for a cleaner solution than this hack of waiting till the
threads are no longer accessible?  Not aware of some indication which kernel
syscall will replace the whole process memory space and the process registers.

It also fixes 11 gdb testsuite failures but these were not analysed from case
to case regarding possible false positives.


Regards,
Jan Kratochvil

[-- Attachment #2: Patch for i386 GDB as of CVS 2006-06-14 --]
[-- Type: text/plain, Size: 7318 bytes --]

Index: i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.69
diff -u -p -r1.69 i386-linux-nat.c
--- i386-linux-nat.c	24 Mar 2006 23:08:16 -0000	1.69
+++ i386-linux-nat.c	14 Jun 2006 10:52:11 -0000
@@ -721,7 +721,19 @@ ps_get_thread_area (const struct ps_proc
 
   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid,
 	      (void *) idx, (unsigned long) &desc) < 0)
-    return PS_ERR;
+    {
+      /* i386: execve(2) will clear the registers including %gs (idx) */
+      if (!idx)
+	{
+	  extern int thread_db_disconnect (void);
+	  if (thread_db_disconnect ())
+	    warning (_("Original threaded process got lost, dropping threads"));
+	  /* Caught by thread_from_lwp() like as TD_THR_ZOMBIE.  */
+	  *(int *)base = 0;
+	  return PS_BADADDR;
+	}
+      return PS_ERR;
+    }
 
   *(int *)base = desc[1];
   return PS_OK;
Index: linux-thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-thread-db.c,v
retrieving revision 1.16
diff -u -p -r1.16 linux-thread-db.c
--- linux-thread-db.c	5 May 2006 22:42:43 -0000	1.16
+++ linux-thread-db.c	14 Jun 2006 10:52:13 -0000
@@ -367,7 +367,12 @@ thread_from_lwp (ptid_t ptid)
 
   gdb_assert (is_lwp (ptid));
 
+  th.th_unique = (psaddr_t) -1;
   err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
+  /* Catch the result from ps_get_thread_area():
+   * Original threaded process got lost, dropping threads  */
+  if (err != TD_OK && th.th_unique == (psaddr_t) 0)
+    return pid_to_ptid (-1);
   if (err != TD_OK)
     error (_("Cannot find user-level thread for LWP %ld: %s"),
 	   GET_LWP (ptid), thread_db_err_str (err));
@@ -1098,22 +1103,36 @@ thread_db_post_startup_inferior (ptid_t 
     }
 }
 
-static void
-thread_db_mourn_inferior (void)
+int
+thread_db_disconnect (void)
 {
+  if (!using_thread_db)
+    return 0;
+
   /* Forget about the child's process ID.  We shouldn't need it
      anymore.  */
   proc_handle.pid = 0;
 
+  /* Detach thread_db target ops.  */
+  unpush_target (&thread_db_ops);
+  using_thread_db = 0;
+
+  return 1;
+}
+
+static void
+thread_db_mourn_inferior (void)
+{
+  int disconnected;
+
   target_beneath->to_mourn_inferior ();
 
   /* Delete the old thread event breakpoints.  Do this after mourning
      the inferior, so that we don't try to uninsert them.  */
   remove_thread_event_breakpoints ();
 
-  /* Detach thread_db target ops.  */
-  unpush_target (&thread_db_ops);
-  using_thread_db = 0;
+  disconnected = thread_db_disconnect ();
+  gdb_assert (disconnected != 0);
 }
 
 static int
Index: testsuite/gdb.threads/thread-lost.c
===================================================================
RCS file: testsuite/gdb.threads/thread-lost.c
diff -N testsuite/gdb.threads/thread-lost.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.threads/thread-lost.c	14 Jun 2006 10:52:18 -0000
@@ -0,0 +1,36 @@
+/* A minimal test case linked with pthreads library.
+
+   Copyright 2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <pthread.h>
+#include <unistd.h>
+
+int main()
+{
+  pthread_t thr;
+  char *cmd_argv[] = { "/bin/echo", "EXECUTED", NULL };
+  char *cmd_env[] = { NULL };
+
+  /* Just ensure we are linked with -lpthread. */
+  thr = pthread_self ();
+
+  return execve (cmd_argv[0], cmd_argv, cmd_env);
+}
Index: testsuite/gdb.threads/thread-lost.exp
===================================================================
RCS file: testsuite/gdb.threads/thread-lost.exp
diff -N testsuite/gdb.threads/thread-lost.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.threads/thread-lost.exp	14 Jun 2006 10:52:18 -0000
@@ -0,0 +1,88 @@
+# Copyright (C) 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# This file was written by Jan Kratochvil <lace@jankratochvil.net>.
+#
+# It tests regression of Red Hat Bug 78228, reported again as Bug 182116.
+# On i386 with %gs based TLS NPTLS gdb calls glibc td_ta_map_lwp2thr() which 
+# calls ta_howto_reg_thread_area() (case ta_howto_reg_thread_area).
+# After execve(2) it retrieves %gs as 0 and fails to ps_get_thread_area()
+# as its idx must be 6 (glibc TLS descriptor) - value of the first/glibc Linux
+# kernel GDT_ENTRY_TLS_MIN.
+# It is now workarounded as to drop threading support if %gs==0.
+
+if $tracelevel then {
+	strace $tracelevel
+}
+
+set testfile "thread-lost"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_run_cmd
+gdb_expect {
+  -re "Original threaded process got lost, dropping threads" {
+    pass "run program to execve(2)"
+  }
+  -re "Cannot find user-level thread for LWP" {
+    fail "GDB did not cope with multithreaded execve(2)"
+  }
+  timeout {
+    fail "run program to execve(2) (timeout)"
+  }
+}
+
+# Only if we would break the execution on:
+# Original threaded process got lost, dropping threads
+###send_gdb "continue\n";
+send_gdb "";
+gdb_expect {
+  -re "EXECUTED" {
+    pass "spawned child got executed"
+  }
+  -re "Cannot find user-level thread for LWP" {
+    fail "GDB did not cope with multithreaded execve(2)"
+  }
+  timeout {
+    fail "spawned child failed to be executed (timeout)"
+  }
+}
+
+send_gdb "quit\n"
+gdb_expect {
+  eof {
+    pass "GDB exits after spawned child finished"
+  }
+  -re "The program is running.  Exit anyway\\? \\(y or n\\) $" {
+    send_gdb "y\n"
+    fail "GDB got stuck after spawned child"
+  }
+  timeout {
+    fail "GDB fails to exit after spawned child"
+  }
+}

[-- Attachment #3: Minimized bug reproducibility test case --]
[-- Type: text/plain, Size: 1142 bytes --]

/* A minimal test case linked with pthreads library.

   Copyright 2006
   Free Software Foundation, Inc.

   This file is part of GDB.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#include <pthread.h>
#include <unistd.h>

int main()
{
  pthread_t thr;
  char *cmd_argv[] = { "/bin/echo", "EXECUTED", NULL };
  char *cmd_env[] = { NULL };

  /* Just ensure we are linked with -lpthread. */
  thr = pthread_self ();

  return execve (cmd_argv[0], cmd_argv, cmd_env);
}

             reply	other threads:[~2006-06-14 10:55 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-14 10:55 Jan Kratochvil [this message]
2006-06-14 14:25 ` Daniel Jacobowitz
2006-06-15 20:36   ` Jan Kratochvil
2006-07-21 18:16     ` Jan Kratochvil
2006-07-21 18:44       ` Daniel Jacobowitz
2006-07-22 12:31         ` Jan Kratochvil
2006-07-24 19:03           ` Daniel Jacobowitz
2006-07-29 18:54             ` [patch] Linux MAY_FOLLOW_EXEC #2 [Re: RFC: Fix crash on i386 (%gs-)threaded programs using execve(2)] Jan Kratochvil
2006-07-31 20:39               ` Mark Kettenis
2006-08-05 16:43                 ` [patch] Linux MAY_FOLLOW_EXEC #2 Jan Kratochvil
2006-08-08 16:01                   ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060614105510.GA12067@host0.dyn.jankratochvil.net \
    --to=lace@jankratochvil.net \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox