From 4e636f80283e919829c390e3c6cca432f4b9cbb3 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 20 Jun 2007 14:25:46 +0000 Subject: [PATCH] - Fix attaching a stopped process on expected + upstream kernels (BZ 233852). - Fix attaching during a pending signal being delivered. --- gdb-6.5-attach-stop.patch | 390 ----------- gdb-6.6-bz233852-attach-signalled.patch | 833 ++++++++++++++++++++++++ gdb.spec | 16 +- 3 files changed, 843 insertions(+), 396 deletions(-) delete mode 100644 gdb-6.5-attach-stop.patch create mode 100644 gdb-6.6-bz233852-attach-signalled.patch diff --git a/gdb-6.5-attach-stop.patch b/gdb-6.5-attach-stop.patch deleted file mode 100644 index c592a4b..0000000 --- a/gdb-6.5-attach-stop.patch +++ /dev/null @@ -1,390 +0,0 @@ -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". - - -2007-03-20 Jan Kratochvil - - * gdb.base/attachstop.exp: Fix an incorrect adaptation on utrace - regression of `kernel-xen-2.6.18-1.2767.el5.i686'. - -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,228 @@ -+# 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}" -+ -+ # Already sent before: after 1000 {send_gdb "\003"} -+ set test "$threadtype: attach2 stop by interrupt" -+ gdb_expect { -+ -re "Program received signal SIGSTOP,.*$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 diff --git a/gdb-6.6-bz233852-attach-signalled.patch b/gdb-6.6-bz233852-attach-signalled.patch new file mode 100644 index 0000000..86b1854 --- /dev/null +++ b/gdb-6.6-bz233852-attach-signalled.patch @@ -0,0 +1,833 @@ +diff -u -rup gdb-6.6-orig/gdb/inf-ptrace.c gdb-6.6/gdb/inf-ptrace.c +--- gdb-6.6-orig/gdb/inf-ptrace.c 2006-01-24 23:34:34.000000000 +0100 ++++ gdb-6.6/gdb/inf-ptrace.c 2007-06-06 13:33:11.000000000 +0200 +@@ -38,6 +38,9 @@ + + /* HACK: Save the ptrace ops returned by inf_ptrace_target. */ + static struct target_ops *ptrace_ops_hack; ++ ++/* Stored PID of the process being stopped during attach. */ ++static pid_t stopped_pid; + + + #ifdef PT_GET_PROCESS_STATE +@@ -69,14 +72,20 @@ inf_ptrace_follow_fork (struct target_op + + if (follow_child) + { ++ unsigned long sig = 0; ++ + inferior_ptid = pid_to_ptid (fpid); + detach_breakpoints (pid); + + /* Reset breakpoints in the child as appropriate. */ + follow_inferior_reset_breakpoints (); + +- if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1) +- perror_with_name (("ptrace")); ++ /* Stop the process again if it was stopped during the attachment. */ ++ if (pid == stopped_pid) ++ sig = target_signal_to_host (TARGET_SIGNAL_STOP)); ++ ++ if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, (void *) sig) == -1) ++ perror_with_name (("ptrace PT_DETACH")); + } + else + { +@@ -173,6 +182,21 @@ inf_ptrace_mourn_inferior (void) + generic_mourn_inferior (); + } + ++/* Wrapper function for waitpid which handles EINTR. */ ++ ++static int ++my_waitpid (int pid, int *status, int flags) ++{ ++ int ret; ++ do ++ { ++ ret = waitpid (pid, status, flags); ++ } ++ while (ret == -1 && errno == EINTR); ++ ++ return ret; ++} ++ + /* Attach to the process specified by ARGS. If FROM_TTY is non-zero, + be chatty about it. */ + +@@ -180,8 +204,14 @@ static void + inf_ptrace_attach (char *args, int from_tty) + { + char *exec_file; +- pid_t pid; ++ pid_t pid, got_pid; + char *dummy; ++ int status; ++ unsigned long sig; ++ FILE *status_file; ++ char name[40]; ++ char buf[100]; ++ int sigstop = target_signal_to_host (TARGET_SIGNAL_STOP); + + if (!args) + error_no_arg (_("process-id to attach")); +@@ -210,11 +240,64 @@ inf_ptrace_attach (char *args, int from_ + } + + #ifdef PT_ATTACH ++ stopped_pid = 0; ++ /* There is a small moment after PTRACE_ATTACH where PTRACE_CONT will ++ succeed only for originally stopped processes. Unfortunately in a moment ++ PTRACE_ATTACH will deliver its SIGSTOP and PTRACE_CONT shows no difference ++ since that moment. ++ "/proc/%d/status" is also a race but it is safe for unstopped cases. */ ++ sprintf (name, "/proc/%d/status", (int) pid); ++ status_file = fopen (name, "r"); ++ if (status_file != NULL) ++ { ++ int have_state = 0; ++ ++ while (fgets (buf, 100, status_file)) ++ { ++ if (strncmp (buf, "State:", 6) == 0) ++ { ++ have_state = 1; ++ break; ++ } ++ } ++ if (have_state != 0 && strstr (buf, "T (stopped)") != NULL) ++ stopped_pid = pid; ++ fclose (status_file); ++ } ++ + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0); + if (errno != 0) + perror_with_name (("ptrace")); + attach_flag = 1; ++ ++ /* Deliver one SIGSTOP just for sure. ++ If the process was already stopped AND some other process (like shell) ++ has already waited for it we would get stuck in waitpid (). */ ++ sig = sigstop; ++ do ++ { ++ if (sig != sigstop) ++ printf_unfiltered (_("Redelivering pending %s.\n"), ++ target_signal_to_string (target_signal_from_host (sig))); ++ errno = 0; ++ ptrace (PT_CONTINUE, pid, (PTRACE_TYPE_ARG3)1, (void *) sig); ++ /* For unstopped processes the preventive signal may ESRCH. */ ++ if (errno != 0 && sig != sigstop) ++ perror_with_name ("ptrace PT_CONTINUE"); ++ ++ got_pid = my_waitpid (pid, &status, 0); ++ gdb_assert (got_pid == pid); ++ ++ /* Check if the thread has exited. */ ++ if (WIFEXITED (status) || WIFSIGNALED (status)) ++ error (_("Program %s exited.\n"), ++ target_pid_to_str (pid_to_ptid (pid))); ++ gdb_assert (WIFSTOPPED (status)); ++ sig = WSTOPSIG (status); ++ gdb_assert (sig != 0); ++ } ++ while (sig != sigstop); + #else + error (_("This system does not support attaching to a process")); + #endif +@@ -240,14 +323,16 @@ inf_ptrace_post_attach (int pid) + + #endif + +-/* Detach from the inferior, optionally passing it the signal +- specified by ARGS. If FROM_TTY is non-zero, be chatty about it. */ ++/* Detach from the inferior. If FROM_TTY is non-zero, be chatty about it. */ + + static void + inf_ptrace_detach (char *args, int from_tty) + { + pid_t pid = ptid_get_pid (inferior_ptid); +- int sig = 0; ++ unsigned long sig = 0; ++ ++ if (args) ++ error (_("Too many arguments")); + + if (from_tty) + { +@@ -258,18 +343,19 @@ inf_ptrace_detach (char *args, int from_ + target_pid_to_str (pid_to_ptid (pid))); + gdb_flush (gdb_stdout); + } +- if (args) +- sig = atoi (args); + + #ifdef PT_DETACH + /* We'd better not have left any breakpoints in the program or it'll + die when it hits one. Also note that this may only work if we + previously attached to the inferior. It *might* work if we + started the process ourselves. */ ++ /* Stop the process again if it was stopped during the attachment. */ ++ if (pid == stopped_pid) ++ sig = target_signal_to_host (TARGET_SIGNAL_STOP); + errno = 0; +- ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig); ++ ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, (void *) sig); + if (errno != 0) +- perror_with_name (("ptrace")); ++ perror_with_name (("ptrace PT_DETACH")); + attach_flag = 0; + #else + error (_("This system does not support detaching from a process")); +@@ -324,6 +410,12 @@ inf_ptrace_resume (ptid_t ptid, int step + single-threaded processes, so simply resume the inferior. */ + pid = ptid_get_pid (inferior_ptid); + ++ /* At this point, we are going to resume the inferior and if we ++ have attached to a stopped process, we no longer should leave ++ it as stopped if the user detaches. */ ++ if (!step && pid == stopped_pid) ++ stopped_pid = 0; ++ + if (step) + { + /* If this system does not support PT_STEP, a higher level +diff -u -rup gdb-6.6-orig/gdb/linux-nat.c gdb-6.6/gdb/linux-nat.c +--- gdb-6.6-orig/gdb/linux-nat.c 2007-06-06 13:30:52.000000000 +0200 ++++ gdb-6.6/gdb/linux-nat.c 2007-06-06 13:57:18.000000000 +0200 +@@ -994,6 +994,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver + { + pid_t pid; + int status; ++ unsigned long sig; + + if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0) + { +@@ -1015,32 +1016,54 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver + "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n", + target_pid_to_str (ptid)); + +- pid = my_waitpid (GET_LWP (ptid), &status, 0); +- if (pid == -1 && errno == ECHILD) ++ sig = SIGSTOP; ++ do + { +- /* Try again with __WCLONE to check cloned processes. */ +- pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE); ++ if (sig != SIGSTOP) ++ printf_unfiltered (_("Redelivering pending %s.\n"), ++ target_signal_to_string (target_signal_from_host (sig))); ++ /* For unstopped processes the preventive signal may ESRCH. */ ++ if (ptrace (PTRACE_CONT, GET_LWP (ptid), (PTRACE_TYPE_ARG3)1, ++ (void *) sig) != 0 && sig != SIGSTOP) ++ perror_with_name ("ptrace"); ++ ++ pid = my_waitpid (GET_LWP (ptid), &status, 0); + if (pid == -1 && errno == ECHILD) +- error (_("Can't attach %s (%s) - possible SELinux denial," +- " check your /var/log/messages for `avc: denied'"), +- target_pid_to_str (ptid), safe_strerror (errno)); +- lp->cloned = 1; +- } ++ { ++ /* Try again with __WCLONE to check cloned processes. */ ++ pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE); ++ if (pid == -1 && errno == ECHILD) ++ error (_("Can't attach %s (%s) - possible SELinux denial," ++ " check your /var/log/messages for `avc: denied'"), ++ target_pid_to_str (ptid), safe_strerror (errno)); ++ lp->cloned = 1; ++ } ++ gdb_assert (pid == GET_LWP (ptid)); + +- gdb_assert (pid == GET_LWP (ptid) +- && WIFSTOPPED (status) && WSTOPSIG (status)); ++ if (debug_linux_nat) ++ { ++ fprintf_unfiltered (gdb_stdlog, ++ "LLAL: waitpid %s received %s\n", ++ target_pid_to_str (ptid), ++ status_to_str (status)); ++ } ++ ++ /* Check if the thread has exited. */ ++ if (WIFEXITED (status) || WIFSIGNALED (status)) ++ { ++ warning (_("Thread %s exited: %s"), target_pid_to_str (ptid), ++ status_to_str (status)); ++ return -1; ++ } ++ gdb_assert (WIFSTOPPED (status)); ++ sig = WSTOPSIG (status); ++ gdb_assert (sig != 0); ++ } ++ while (sig != SIGSTOP); + + target_post_attach (pid); + + lp->stopped = 1; +- +- if (debug_linux_nat) +- { +- fprintf_unfiltered (gdb_stdlog, +- "LLAL: waitpid %s received %s\n", +- target_pid_to_str (ptid), +- status_to_str (status)); +- } + } + else + { +@@ -1065,8 +1088,6 @@ static void + linux_nat_attach (char *args, int from_tty) + { + struct lwp_info *lp; +- pid_t pid; +- int status; + + /* FIXME: We should probably accept a list of process id's, and + attach all of them. */ +@@ -1076,22 +1097,6 @@ linux_nat_attach (char *args, int from_t + inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)); + lp = add_lwp (inferior_ptid); + +- /* Make sure the initial process is stopped. The user-level threads +- layer might want to poke around in the inferior, and that won't +- work if things haven't stabilized yet. */ +- pid = my_waitpid (GET_PID (inferior_ptid), &status, 0); +- if (pid == -1 && errno == ECHILD) +- { +- warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid)); +- +- /* Try again with __WCLONE to check cloned processes. */ +- pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE); +- lp->cloned = 1; +- } +- +- gdb_assert (pid == GET_PID (inferior_ptid) +- && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP); +- + lp->stopped = 1; + + /* Fake the SIGSTOP that core GDB expects. */ +@@ -1099,8 +1104,8 @@ linux_nat_attach (char *args, int from_t + lp->resumed = 1; + if (debug_linux_nat) + { +- fprintf_unfiltered (gdb_stdlog, +- "LLA: waitpid %ld, faking SIGSTOP\n", (long) pid); ++ fprintf_unfiltered (gdb_stdlog, "LLA: waitpid %d, faking SIGSTOP\n", ++ GET_PID (inferior_ptid)); + } + } + +diff -u -rup gdb-6.6-orig/gdb/target.h gdb-6.6/gdb/target.h +--- gdb-6.6-orig/gdb/target.h 2007-06-06 13:30:52.000000000 +0200 ++++ gdb-6.6/gdb/target.h 2007-06-06 13:33:11.000000000 +0200 +@@ -529,9 +529,9 @@ void target_close (struct target_ops *ta + to the `attach' command by the user. This routine can be called + when the target is not on the target-stack, if the target_can_run + routine returns 1; in that case, it must push itself onto the stack. +- Upon exit, the target should be ready for normal operations, and +- should be ready to deliver the status of the process immediately +- (without waiting) to an upcoming target_wait call. */ ++ Upon exit, the target should be ready for normal operations. ++ The status of the inferior is already processed and possibly pending ++ signals redelivered. */ + + #define target_attach(args, from_tty) \ + (*current_target.to_attach) (args, from_tty) +diff -u -rup gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-into-signal.c gdb-6.6/gdb/testsuite/gdb.threads/attach-into-signal.c +--- gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-into-signal.c 2007-06-06 16:36:34.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/attach-into-signal.c 2007-06-06 13:33:11.000000000 +0200 +@@ -0,0 +1,65 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2007 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. */ ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef USE_THREADS ++#include ++#endif ++ ++void action(int sig, siginfo_t * info, void *uc) ++{ ++ raise (SIGALRM); ++} ++ ++static void *func (void *arg) ++{ ++ struct sigaction act; ++ ++ memset (&act, 0, sizeof(struct sigaction)); ++ act.sa_sigaction = action; ++ act.sa_flags = SA_RESTART; ++ sigaction (SIGALRM, &act, 0); ++ ++ raise (SIGALRM); ++ ++ abort (); ++ /* NOTREACHED */ ++ 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 -rup gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-into-signal.exp gdb-6.6/gdb/testsuite/gdb.threads/attach-into-signal.exp +--- gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-into-signal.exp 2007-06-06 16:36:34.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/attach-into-signal.exp 2007-06-06 13:33:11.000000000 +0200 +@@ -0,0 +1,153 @@ ++# Copyright 2007 ++ ++# 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-stopped.exp. ++# This file was created by Jan Kratochvil . ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set prms_id 0 ++set bug_id 0 ++ ++set testfile "attach-into-signal" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++set escapedbinfile [string_to_regexp ${objdir}/${subdir}/${testfile}] ++ ++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. ++ # Statistically there is a better chance without giving process a nice. ++ ++ set testpid [eval exec $binfile &] ++ exec sleep 2 ++ ++ # Run 2 passes of the test. ++ # The C file inferior stops pending its signals if a single one is lost, ++ # we test successful redelivery of the caught signal by the 2nd pass. ++ ++ # linux-2.6.20.4.x86_64 had maximal attempt # 20 in 4 test runs. ++ set attempts 100 ++ set attempt 0 ++ set passes 1 ++ while { $passes < 3 && $attempt < $attempts } { ++ ++ # Start with clean gdb ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile} ++ ++ # No PASS message as we may be looping in multiple attempts. ++ gdb_test "set debug lin-lwp 1" "" "" ++ ++ set test "$threadtype: set file (pass $passes), before attach1 to stopped process" ++ if {[gdb_test_multiple "file $binfile" $test { ++ -re "Load new symbol table from.*y or n. $" { ++ # No PASS message as we may be looping in multiple attempts. ++ gdb_test "y" "Reading symbols from $escapedbinfile\.\.\.*done." "" ++ } ++ -re "Reading symbols from $escapedbinfile\.\.\.*done.*$gdb_prompt $" { ++ # No PASS message as we may be looping in multiple attempts. ++ } ++ }] != 0 } { ++ break ++ } ++ ++ # Main test: ++ set test "$threadtype: attach (pass $passes), pending signal catch" ++ if {[gdb_test_multiple "attach $testpid" $test { ++ -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*Redelivering pending Alarm clock..*$gdb_prompt $" { ++ # nonthreaded: ++ pass $test ++ verbose -log "$test succeeded on the attempt # $attempt of $attempts" ++ set passes [expr $passes + 1] ++ } ++ -re "Attaching to program.*`?$escapedbinfile'?, process $testpid.*$gdb_prompt $" { ++ # nonthreaded: ++ # We just lack the luck, we should try it again. ++ set attempt [expr $attempt + 1] ++ } ++ -re "Attaching to process $testpid.*Redelivering pending Alarm clock..*$gdb_prompt $" { ++ # threaded: ++ pass $test ++ verbose -log "$test succeeded on the attempt # $attempt of $attempts" ++ set passes [expr $passes + 1] ++ } ++ -re "Attaching to process $testpid.*$gdb_prompt $" { ++ # threaded: ++ # We just lack the luck, we should try it again. ++ set attempt [expr $attempt - 1] ++ } ++ }] != 0 } { ++ break ++ } ++ } ++ if {$passes < 3} { ++ fail $test ++ } ++ ++ # Exit and detach the process. ++ ++ gdb_exit ++ ++ # 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. ++ ++ # Continue the program - some Linux kernels need it before -9 if the ++ # process is stopped. ++ remote_exec build "kill -s CONT ${testpid}" ++ ++ 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 +diff -u -rup gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-stopped.c gdb-6.6/gdb/testsuite/gdb.threads/attach-stopped.c +--- gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-stopped.c 2007-06-06 16:36:34.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/attach-stopped.c 2007-06-06 13:33:11.000000000 +0200 +@@ -0,0 +1,51 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2005-2007 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 -rup gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-stopped.exp gdb-6.6/gdb/testsuite/gdb.threads/attach-stopped.exp +--- gdb-6.6-orig/gdb/testsuite/gdb.threads/attach-stopped.exp 2007-06-06 16:36:34.000000000 +0200 ++++ gdb-6.6/gdb/testsuite/gdb.threads/attach-stopped.exp 2007-06-06 13:33:11.000000000 +0200 +@@ -0,0 +1,208 @@ ++# Copyright 2005-2007 ++ ++# 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 "attach-stopped" ++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 interrupt" ++ gdb_expect 10 { ++ -re "Program received signal SIGINT.*$gdb_prompt $" ++ { ++ pass $test ++ } ++ -re "Breakpoint \[0-9\].*$srcfile.*$gdb_prompt $" ++ { ++ pass $test ++ } ++ timeout ++ { ++ fail $test ++ } ++ } ++ ++ 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 diff --git a/gdb.spec b/gdb.spec index 0df1007..22641b9 100644 --- a/gdb.spec +++ b/gdb.spec @@ -11,7 +11,7 @@ Name: gdb Version: 6.6 # The release always contains a leading reserved number, start it at 1. -Release: 15%{?dist} +Release: 16%{?dist} License: GPL Group: Development/Debuggers @@ -222,10 +222,6 @@ Patch190: gdb-6.5-dwarf-stack-overflow.patch # Fix gdb printf command argument using "%p" (BZ 205551). Patch191: gdb-6.5-bz205551-printf-p.patch -# Fix attach to stopped process, supersede `gdb-6.3-attach-stop-20051011.patch'. -# Fix attachment also to a threaded stopped process (BZ 219118). -Patch193: gdb-6.5-attach-stop.patch - # Support TLS symbols (+`errno' suggestion if no pthread is found) (BZ 185337). # FIXME: Still to be updated. Patch194: gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch @@ -350,6 +346,10 @@ Patch251: gdb-6.5-bz237872-ppc-long-double.patch # Avoid too long timeouts on failing cases of "annota1.exp annota3.exp". Patch254: gdb-6.6-testsuite-timeouts.patch +# Fix attaching a stopped nonthreaded/threaded process (BZ 219118, 233852). +# Fix attaching during a pending signal being delivered. +Patch256: gdb-6.6-bz233852-attach-signalled.patch + BuildRequires: ncurses-devel glibc-devel gcc make gzip texinfo dejagnu gettext BuildRequires: flex bison sharutils expat-devel @@ -448,7 +448,6 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c %patch188 -p1 %patch190 -p1 %patch191 -p1 -%patch193 -p1 %patch194 -p1 %patch195 -p1 %patch196 -p1 @@ -494,6 +493,7 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c %patch249 -p1 %patch251 -p1 %patch254 -p1 +%patch256 -p1 # Change the version that gets printed at GDB startup, so it is RedHat # specific. @@ -643,6 +643,10 @@ fi # don't include the files in include, they are part of binutils %changelog +* Wed Jun 20 2007 Jan Kratochvil - 6.6-16 +- Fix attaching a stopped process on expected + upstream kernels (BZ 233852). + - Fix attaching during a pending signal being delivered. + * Thu Jun 7 2007 Jan Kratochvil - 6.6-15 - Testcase update to cover PPC Power6/DFP instructions disassembly (BZ 230000). - Disable some known timeouting/failing testcases to reduce the build time.