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 +#include + +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 . +# +# 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" + } +}