https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=209521 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=219118 http://sources.redhat.com/ml/gdb-patches/2006-09/msg00092.html Specific to Red Hat kernels, kernel.org kernels lockup on gdb "attach". 2006-12-11 Jan Kratochvil * gdb-6.5/gdb/linux-nat.c (linux_nat_attach): Handle already stopped processes, compiled either in a nonthreaded or a threaded mode. 2006-12-11 Jeff Johnston Jan Kratochvil * gdb.base/attachstop.exp, gdb.base/attachstop.c: New files, test attaching to already stopped processes, compiled either in a nonthreaded or a threaded mode. diff -u -ruNp gdb-6.5-orig/gdb/linux-nat.c gdb-6.5/gdb/linux-nat.c --- gdb-6.5-orig/gdb/linux-nat.c 2006-12-12 00:30:18.000000000 +0100 +++ gdb-6.5/gdb/linux-nat.c 2006-12-11 23:42:23.000000000 +0100 @@ -567,7 +567,9 @@ linux_handle_extended_wait (int pid, int else if (ret != new_pid) internal_error (__FILE__, __LINE__, _("wait returned unexpected PID %d"), ret); - else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP) + /* In some cases we get 0 for the `SIGSTOP' signal. */ + else if (!WIFSTOPPED (status) || + (WSTOPSIG (status) != SIGSTOP && WSTOPSIG (status) != 0)) internal_error (__FILE__, __LINE__, _("wait returned unexpected status 0x%x"), status); } @@ -1007,8 +1009,9 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver lp->cloned = 1; } + /* In some cases we get 0 for the `SIGSTOP' signal. */ gdb_assert (pid == GET_LWP (ptid) - && WIFSTOPPED (status) && WSTOPSIG (status)); + && WIFSTOPPED (status)); target_post_attach (pid); @@ -1062,13 +1065,14 @@ linux_nat_attach (char *args, int from_t lp->cloned = 1; } - gdb_assert (pid == GET_PID (inferior_ptid) - && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); + /* In some cases we get 0 for the `SIGSTOP' signal. */ + gdb_assert (pid == GET_PID (inferior_ptid) && WIFSTOPPED (status) + && (WSTOPSIG (status) == SIGSTOP || WSTOPSIG (status) == 0)); lp->stopped = 1; - /* Fake the SIGSTOP that core GDB expects. */ - lp->status = W_STOPCODE (SIGSTOP); + /* Provide the stop status that core GDB expects. */ + lp->status = status; lp->resumed = 1; if (debug_linux_nat) { @@ -1509,7 +1513,8 @@ stop_wait_callback (struct lwp_info *lp, return stop_wait_callback (lp, flush_mask); } - if (WSTOPSIG (status) != SIGSTOP) + /* In some cases we get 0 for the `SIGSTOP' signal. */ + if (WSTOPSIG (status) != SIGSTOP && WSTOPSIG (status) != 0) { if (WSTOPSIG (status) == SIGTRAP) { @@ -2093,8 +2098,10 @@ retry: if (options & __WCLONE) lp->cloned = 1; + /* In some cases we get 0 for the `SIGSTOP' signal. */ gdb_assert (WIFSTOPPED (status) - && WSTOPSIG (status) == SIGSTOP); + && (WSTOPSIG (status) == SIGSTOP + || WSTOPSIG (status) == 0)); lp->signalled = 1; if (!in_thread_list (inferior_ptid)) @@ -2195,8 +2202,10 @@ retry: /* Make sure we don't report a SIGSTOP that we sent ourselves in an attempt to stop an LWP, unless we intentionally want to see the SIGSTOP. */ + /* In some cases we get 0 for the `SIGSTOP' signal. */ if (lp->signalled && !intentional_stop - && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP) + && WIFSTOPPED (status) && (WSTOPSIG (status) == SIGSTOP + || WSTOPSIG (status) == 0)) { if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, diff -u -ruNp gdb-6.5-orig/gdb/testsuite/gdb.base/attachstop.c gdb-6.5/gdb/testsuite/gdb.base/attachstop.c --- gdb-6.5-orig/gdb/testsuite/gdb.base/attachstop.c 1970-01-01 01:00:00.000000000 +0100 +++ gdb-6.5/gdb/testsuite/gdb.base/attachstop.c 2006-12-11 23:58:22.000000000 +0100 @@ -0,0 +1,51 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2005 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. */ + +/* This program is intended to be started outside of gdb, then + manually stopped via a signal. */ + +#include +#include +#ifdef USE_THREADS +#include +#endif + +static void *func (void *arg) +{ + sleep (10000); /* Ridiculous time, but we will eventually kill it. */ + sleep (10000); /* Second sleep. */ + return NULL; +} + +int main () +{ + +#ifndef USE_THREADS + + func (NULL); + +#else + + pthread_t th; + pthread_create (&th, NULL, func, NULL); + pthread_join (th, NULL); + +#endif + + return 0; +} diff -u -ruNp gdb-6.5-orig/gdb/testsuite/gdb.base/attachstop.exp gdb-6.5/gdb/testsuite/gdb.base/attachstop.exp --- gdb-6.5-orig/gdb/testsuite/gdb.base/attachstop.exp 1970-01-01 01:00:00.000000000 +0100 +++ gdb-6.5/gdb/testsuite/gdb.base/attachstop.exp 2006-12-12 00:26:39.000000000 +0100 @@ -0,0 +1,234 @@ +# Copyright 2005-2006 + +# 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. + +# This test was created by modifying attach.exp. +# This file was created by Jeff Johnston . +# This file was updated by Jan Kratochvil . + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +# This test only works on Linux +if { ![istarget "*-*-linux-gnu*"] } { + return 0 +} + +set testfile "attachstop" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +set escapedbinfile [string_to_regexp ${objdir}/${subdir}/${testfile}] + +#execute_anywhere "rm -f ${binfile}" +remote_exec build "rm -f ${binfile}" +# For debugging this test +# +#log_user 1 + +proc corefunc { threadtype } { + global srcfile + global binfile + global escapedbinfile + global srcdir + global subdir + global gdb_prompt + + if [get_compiler_info ${binfile}] { + return -1 + } + + # Start the program running and then wait for a bit, to be sure + # that it can be attached to. + + set testpid [eval exec $binfile &] + exec sleep 2 + + # Stop the program + remote_exec build "kill -s STOP ${testpid}" + + # Start with clean gdb + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + + # Verify that we can attach to the process by first giving its + # executable name via the file command, and using attach with the + # process ID. + + set test "$threadtype: set file, before attach1 to stopped process" + gdb_test_multiple "file $binfile" "$test" { + -re "Load new symbol table from.*y or n. $" { + gdb_test "y" "Reading symbols from $escapedbinfile\.\.\.*done." \ + "$test (re-read)" + } + -re "Reading symbols from $escapedbinfile\.\.\.*done.*$gdb_prompt $" { + pass "$test" + } + } + + set test "$threadtype: attach1 to stopped, after setting file" + gdb_test_multiple "attach $testpid" "$test" { + -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*$gdb_prompt $" { + pass "$test" + } + } + + if {[string equal $threadtype threaded]} { + gdb_test "thread apply all bt" ".*sleep.*clone.*" "$threadtype: attach1 to stopped bt" + } else { + gdb_test "bt" ".*sleep.*main.*" "$threadtype: attach1 to stopped bt" + } + + # Exit and detach the process. + + gdb_exit + + set fileid [open /proc/${testpid}/status r]; + gets $fileid line1; + gets $fileid line2; + close $fileid; + + set test "$threadtype: attach1, exit leaves process stopped" + if {[string match "*(stopped)*" $line2]} { + pass $test + } else { + fail $test + } + + # At this point, the process should still be stopped + + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} + + # Verify that we can attach to the process just by giving the + # process ID. + + set test "$threadtype: attach2 to stopped, after setting file" + gdb_test_multiple "attach $testpid" "$test" { + -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*$gdb_prompt $" { + pass "$test" + } + } + + if {[string equal $threadtype threaded]} { + gdb_test "thread apply all bt" ".*sleep.*clone.*" "$threadtype: attach2 to stopped bt" + } else { + gdb_test "bt" ".*sleep.*main.*" "$threadtype: attach2 to stopped bt" + } + gdb_breakpoint [gdb_get_line_number "$threadtype: Second sleep"] + set test "$threadtype: attach2 continue" + send_gdb "continue\n" + gdb_expect { + -re "Continuing" + { pass "continue ($test)" } + timeout + { fail "continue ($test) (timeout)" } + } + + # For this to work we must be sure to consume the "Continuing." + # message first, or GDB's signal handler may not be in place. + after 1000 {send_gdb "\003"} + set test "$threadtype: attach2 stop unbreakable interrupt" + gdb_expect 4 { + -re "Program received signal SIGINT.*$gdb_prompt $" + { + fail "$test (broke into)" + } + -re "Breakpoint \[0-9\].*$srcfile.*$gdb_prompt $" + { + fail "$test (broke into)" + } + timeout + { + pass $test + } + } + + # Continue the program + remote_exec build "kill -s CONT ${testpid}" + + if {[string equal $threadtype threaded]} { + # Isn't a bug? kernel-xen-2.6.18-1.2767.el5.i686 + set signal_expect "SIGCONT" + } else { + set signal_expect "SIGINT" + } + # Already sent before: after 1000 {send_gdb "\003"} + set test "$threadtype: attach2 stop by interrupt" + gdb_expect { + -re "Program received signal $signal_expect,.*$gdb_prompt $" + { + pass $test + } + -re "Breakpoint \[0-9\].*$srcfile.*$gdb_prompt $" + { + pass $test + } + timeout + { + fail "$test (timeout)" + } + } + + gdb_exit + + # Avoid some race: + exec sleep 2 + + # At this point, the process should be sleeping + + set fileid2 [open /proc/${testpid}/status r]; + gets $fileid2 line1; + gets $fileid2 line2; + close $fileid2; + + set test "$threadtype: attach2, exit leaves process sleeping" + if {[string match "*(sleeping)*" $line2]} { + pass $test + } else { + fail $test + } + + # Make sure we don't leave a process around to confuse + # the next test run (and prevent the compile by keeping + # the text file busy), in case the "set should_exit" didn't + # work. + + remote_exec build "kill -9 ${testpid}" +} + +# build the test case first without threads +# +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase nonthraded compile failed, so all tests in this file will automatically fail." +} + +corefunc nonthreaded + +# build the test case first without threads +# +if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DUSE_THREADS}] != "" } { + gdb_suppress_entire_file "Testcase threaded compile failed, so all tests in this file will automatically fail." +} + +corefunc threaded + +return 0