- Fix attaching a stopped process on expected + upstream kernels (BZ

233852).
- Fix attaching during a pending signal being delivered.
This commit is contained in:
Jan Kratochvil 2007-06-20 14:25:46 +00:00
parent aad703f07a
commit 4e636f8028
3 changed files with 843 additions and 396 deletions

View File

@ -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 <jan.kratochvil@redhat.com>
* 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 <jan.kratochvil@redhat.com>
* 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 <jjohnstn@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* 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 <stddef.h>
+#include <unistd.h>
+#ifdef USE_THREADS
+#include <pthread.h>
+#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 <jjohnstn@redhat.com>.
+# This file was updated by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+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

View File

@ -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 <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef USE_THREADS
+#include <pthread.h>
+#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 <jan.kratochvil@redhat.com>.
+
+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 <stddef.h>
+#include <unistd.h>
+#ifdef USE_THREADS
+#include <pthread.h>
+#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 <jjohnstn@redhat.com>.
+# This file was updated by Jan Kratochvil <jan.kratochvil@redhat.com>.
+
+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

View File

@ -11,7 +11,7 @@ Name: gdb
Version: 6.6 Version: 6.6
# The release always contains a leading reserved number, start it at 1. # The release always contains a leading reserved number, start it at 1.
Release: 15%{?dist} Release: 16%{?dist}
License: GPL License: GPL
Group: Development/Debuggers Group: Development/Debuggers
@ -222,10 +222,6 @@ Patch190: gdb-6.5-dwarf-stack-overflow.patch
# Fix gdb printf command argument using "%p" (BZ 205551). # Fix gdb printf command argument using "%p" (BZ 205551).
Patch191: gdb-6.5-bz205551-printf-p.patch 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). # Support TLS symbols (+`errno' suggestion if no pthread is found) (BZ 185337).
# FIXME: Still to be updated. # FIXME: Still to be updated.
Patch194: gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch 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". # Avoid too long timeouts on failing cases of "annota1.exp annota3.exp".
Patch254: gdb-6.6-testsuite-timeouts.patch 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: ncurses-devel glibc-devel gcc make gzip texinfo dejagnu gettext
BuildRequires: flex bison sharutils expat-devel 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 %patch188 -p1
%patch190 -p1 %patch190 -p1
%patch191 -p1 %patch191 -p1
%patch193 -p1
%patch194 -p1 %patch194 -p1
%patch195 -p1 %patch195 -p1
%patch196 -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 %patch249 -p1
%patch251 -p1 %patch251 -p1
%patch254 -p1 %patch254 -p1
%patch256 -p1
# Change the version that gets printed at GDB startup, so it is RedHat # Change the version that gets printed at GDB startup, so it is RedHat
# specific. # specific.
@ -643,6 +643,10 @@ fi
# don't include the files in include, they are part of binutils # don't include the files in include, they are part of binutils
%changelog %changelog
* Wed Jun 20 2007 Jan Kratochvil <jan.kratochvil@redhat.com> - 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 <jan.kratochvil@redhat.com> - 6.6-15 * Thu Jun 7 2007 Jan Kratochvil <jan.kratochvil@redhat.com> - 6.6-15
- Testcase update to cover PPC Power6/DFP instructions disassembly (BZ 230000). - Testcase update to cover PPC Power6/DFP instructions disassembly (BZ 230000).
- Disable some known timeouting/failing testcases to reduce the build time. - Disable some known timeouting/failing testcases to reduce the build time.