- Support for stepping over PPC atomic instruction sequences (BZ 237572).

- `set scheduler-locking step' is no longer enforced but it is now default.
This commit is contained in:
Jan Kratochvil 2007-06-21 05:22:01 +00:00
parent 4e636f8028
commit 5a72cdabf8
8 changed files with 1887 additions and 496 deletions

View File

@ -0,0 +1,178 @@
2005-02-11 Jeff Johnston <jjohnstn@redhat.com>
* testsuite/gdb.threads/step-thread-exit.c: New testcase.
* testsuite/gdb.threads/step-thread-exit.exp: Ditto.
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c 2006-07-12 03:18:47.000000000 -0300
@@ -0,0 +1,50 @@
+/* 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. */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void *thread_function (void *ptr)
+{
+ int *x = (int *)ptr;
+ printf("In thread_function, *x is %d\n", *x);
+} /* thread_function_end */
+
+volatile int repeat = 0;
+
+main()
+{
+ int ret;
+ pthread_t th;
+ int i = 3;
+
+ ret = pthread_create (&th, NULL, thread_function, &i);
+ do
+ {
+ repeat = 0;
+ sleep (3); /* sleep */
+ }
+ while (repeat);
+ pthread_join (th, NULL);
+ return 0;
+}
+
+
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp 2006-07-12 03:22:30.000000000 -0300
@@ -0,0 +1,113 @@
+# 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.
+
+# Check that GDB can step over a thread exit.
+
+if $tracelevel {
+ strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "step-thread-exit"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Reset the debug file directory so we can't debug within the C library
+gdb_test "set debug-file-directory ." "" ""
+
+#
+# Run to `main' where we begin our tests.
+#
+
+if ![runto_main] then {
+ gdb_suppress_tests
+}
+
+set sleep_line [expr [gdb_get_line_number "sleep"]]
+set end_line [expr [gdb_get_line_number "thread_function_end"]]
+
+gdb_breakpoint "$end_line"
+gdb_test "continue" "Break.*thread_function.*" "continue to thread_function 1"
+
+# Keep nexting until we cause the thread to exit. We expect the main
+# thread to be stopped and a message printed to tell us we have stepped
+# over the thread exit.
+set test "step over thread exit 1"
+gdb_test_multiple "next" "$test" {
+ -re "\}.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+ -re "Stepped over thread exit.*Program received signal SIGSTOP.*$gdb_prompt $" {
+ pass "$test"
+ }
+ -re "start_thread.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+}
+
+gdb_test "bt" ".*sleep.*main.*$sleep_line.*" "backtrace after step 1"
+
+runto_main
+gdb_breakpoint "$sleep_line"
+gdb_breakpoint "$end_line"
+set test "continue to thread_function 2"
+gdb_test_multiple "continue" "$test" {
+ -re "Break.*thread_function.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "Break.*$sleep_line.*$gdb_prompt $" {
+ gdb_test "set repeat=1" "" ""
+ send_gdb "continue\n"
+ exp_continue
+ }
+}
+
+# Keep nexting until we cause the thread to exit. In this case, we
+# expect the breakpoint in the main thread to have already triggered
+# and so we should stop there with a message that we stepped over
+# the thread exit.
+set test "step over thread exit 2"
+gdb_test_multiple "next" "$test" {
+ -re "\}.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+ -re "Stepped over thread exit.*Break.*$sleep_line.*$gdb_prompt $" {
+ pass "$test (breakpoint hit)"
+ }
+ -re "Stepped over thread exit.*$gdb_prompt $" {
+ pass "$test (breakpoint not hit)"
+ }
+ -re "start_thread.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+}
+

View File

@ -1,433 +0,0 @@
2005-02-11 Jeff Johnston <jjohnstn@redhat.com>
* target.h (target_waitstatus): Add new step_thread_exit flag.
* infrun.c (init_execution_control_state): Initialize step_thread_exit.
(handle_inferior_event): If step_thread_exit flag is set, print
out special message and reset flag.
(currently_stepping): Do not return true if step_thread_exit flag
is set.
* linux-nat.c (resume_callback): Use second parameter to notify
if the resume should be a PTRACE_SINGLESTEP or PTRACE_CONT.
(stop_and_resume_callback): Pass on data parameter to resume_callback.
(linux_nat_resume): Don't attempt to resume if lp is NULL.
(linux_nat_wait): Do not wait on step_lp as first wait. After
wait, check if step_lp has an event or not. If the step lwp has
exited, issue a stop on the first non-step_lp lwp in the lwp list.
Change the delayed stop code to not ignore an intentional stop.
If we see an event on an lwp which isn't the step_lp, verify if
the step_lp has exited or not. Set the step_thread_exit flag if
we have verified that the step_lp is gone.
* testsuite/gdb.threads/step-thread-exit.c: New testcase.
* testsuite/gdb.threads/step-thread-exit.exp: Ditto.
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.c 2006-07-12 03:18:47.000000000 -0300
@@ -0,0 +1,50 @@
+/* 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. */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void *thread_function (void *ptr)
+{
+ int *x = (int *)ptr;
+ printf("In thread_function, *x is %d\n", *x);
+} /* thread_function_end */
+
+volatile int repeat = 0;
+
+main()
+{
+ int ret;
+ pthread_t th;
+ int i = 3;
+
+ ret = pthread_create (&th, NULL, thread_function, &i);
+ do
+ {
+ repeat = 0;
+ sleep (3); /* sleep */
+ }
+ while (repeat);
+ pthread_join (th, NULL);
+ return 0;
+}
+
+
Index: gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.5/gdb/testsuite/gdb.threads/step-thread-exit.exp 2006-07-12 03:22:30.000000000 -0300
@@ -0,0 +1,113 @@
+# 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.
+
+# Check that GDB can step over a thread exit.
+
+if $tracelevel {
+ strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "step-thread-exit"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Reset the debug file directory so we can't debug within the C library
+gdb_test "set debug-file-directory ." "" ""
+
+#
+# Run to `main' where we begin our tests.
+#
+
+if ![runto_main] then {
+ gdb_suppress_tests
+}
+
+set sleep_line [expr [gdb_get_line_number "sleep"]]
+set end_line [expr [gdb_get_line_number "thread_function_end"]]
+
+gdb_breakpoint "$end_line"
+gdb_test "continue" "Break.*thread_function.*" "continue to thread_function 1"
+
+# Keep nexting until we cause the thread to exit. We expect the main
+# thread to be stopped and a message printed to tell us we have stepped
+# over the thread exit.
+set test "step over thread exit 1"
+gdb_test_multiple "next" "$test" {
+ -re "\}.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+ -re "Stepped over thread exit.*Program received signal SIGSTOP.*$gdb_prompt $" {
+ pass "$test"
+ }
+ -re "start_thread.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+}
+
+gdb_test "bt" ".*sleep.*main.*$sleep_line.*" "backtrace after step 1"
+
+runto_main
+gdb_breakpoint "$sleep_line"
+gdb_breakpoint "$end_line"
+set test "continue to thread_function 2"
+gdb_test_multiple "continue" "$test" {
+ -re "Break.*thread_function.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "Break.*$sleep_line.*$gdb_prompt $" {
+ gdb_test "set repeat=1" "" ""
+ send_gdb "continue\n"
+ exp_continue
+ }
+}
+
+# Keep nexting until we cause the thread to exit. In this case, we
+# expect the breakpoint in the main thread to have already triggered
+# and so we should stop there with a message that we stepped over
+# the thread exit.
+set test "step over thread exit 2"
+gdb_test_multiple "next" "$test" {
+ -re "\}.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+ -re "Stepped over thread exit.*Break.*$sleep_line.*$gdb_prompt $" {
+ pass "$test (breakpoint hit)"
+ }
+ -re "Stepped over thread exit.*$gdb_prompt $" {
+ pass "$test (breakpoint not hit)"
+ }
+ -re "start_thread.*$gdb_prompt $" {
+ send_gdb "next\n"
+ exp_continue
+ }
+}
+
Index: gdb-6.5/gdb/infrun.c
===================================================================
--- gdb-6.5.orig/gdb/infrun.c 2006-07-12 01:54:29.000000000 -0300
+++ gdb-6.5/gdb/infrun.c 2006-07-12 03:22:41.000000000 -0300
@@ -1088,6 +1088,7 @@ init_execution_control_state (struct exe
ecs->current_symtab = ecs->sal.symtab;
ecs->infwait_state = infwait_normal_state;
ecs->waiton_ptid = pid_to_ptid (-1);
+ ecs->ws.step_thread_exit = 0;
ecs->wp = &(ecs->ws);
}
@@ -1307,6 +1308,16 @@ handle_inferior_event (struct execution_
ui_out_text (uiout, "]\n");
}
+ /* Check if were stepping a thread and we stepped over the exit.
+ In such a case, we will have found another event to process.
+ Clear any stepping state and process that event. */
+ if (ecs->ws.step_thread_exit)
+ {
+ printf_unfiltered ("[Stepped over thread exit]\n");
+ clear_proceed_status ();
+ ecs->ws.step_thread_exit = 0;
+ }
+
switch (ecs->ws.kind)
{
case TARGET_WAITKIND_LOADED:
@@ -2697,11 +2708,12 @@ process_event_stop_test:
static int
currently_stepping (struct execution_control_state *ecs)
{
- return ((!ecs->handling_longjmp
- && ((step_range_end && step_resume_breakpoint == NULL)
- || trap_expected))
- || ecs->stepping_through_solib_after_catch
- || bpstat_should_step ());
+ return (!ecs->ws.step_thread_exit
+ && ((!ecs->handling_longjmp
+ && ((step_range_end && step_resume_breakpoint == NULL)
+ || trap_expected))
+ || ecs->stepping_through_solib_after_catch
+ || bpstat_should_step ()));
}
/* Subroutine call with source code we should not step over. Do step
Index: gdb-6.5/gdb/linux-nat.c
===================================================================
--- gdb-6.5.orig/gdb/linux-nat.c 2006-07-12 01:54:29.000000000 -0300
+++ gdb-6.5/gdb/linux-nat.c 2006-07-12 03:22:42.000000000 -0300
@@ -1137,18 +1137,21 @@ linux_nat_detach (char *args, int from_t
static int
resume_callback (struct lwp_info *lp, void *data)
{
+ int step = (data != NULL);
+
if (lp->stopped && lp->status == 0)
{
struct thread_info *tp;
linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
- 0, TARGET_SIGNAL_0);
+ step, TARGET_SIGNAL_0);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
- "RC: PTRACE_CONT %s, 0, 0 (resume sibling)\n",
+ "RC: %s %s, 0, 0 (resume sibling)\n",
+ step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
target_pid_to_str (lp->ptid));
lp->stopped = 0;
- lp->step = 0;
+ lp->step = step;
}
return 0;
@@ -1259,13 +1262,17 @@ linux_nat_resume (ptid_t ptid, int step,
if (resume_all)
iterate_over_lwps (resume_callback, NULL);
- linux_ops->to_resume (ptid, step, signo);
- if (debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog,
- "LLR: %s %s, %s (resume event thread)\n",
- step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
- target_pid_to_str (ptid),
- signo ? strsignal (signo) : "0");
+ if (lp)
+ {
+ linux_ops->to_resume (ptid, step, signo);
+
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLR: %s %s, %s (resume event thread)\n",
+ step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+ target_pid_to_str (ptid),
+ signo ? strsignal (signo) : "0");
+ }
}
/* Issue kill to specified lwp. */
@@ -1863,7 +1870,7 @@ stop_and_resume_callback (struct lwp_inf
for (ptr = lwp_list; ptr; ptr = ptr->next)
if (lp == ptr)
{
- resume_callback (lp, NULL);
+ resume_callback (lp, data);
resume_set_callback (lp, NULL);
}
}
@@ -1874,8 +1881,10 @@ static ptid_t
linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
struct lwp_info *lp = NULL;
+ struct lwp_info *step_lp = NULL;
int options = 0;
int status = 0;
+ int intentional_stop = 0;
pid_t pid = PIDGET (ptid);
sigset_t flush_mask;
@@ -1913,14 +1922,12 @@ retry:
gets the expected trap so we don't want to wait on any LWP.
This has ramifications when adjustment of the PC is required which can be
different after a breakpoint vs a step (e.g. x86). */
- lp = iterate_over_lwps (find_singlestep_lwp_callback, NULL);
- if (lp) {
+ step_lp = iterate_over_lwps (find_singlestep_lwp_callback, NULL);
+ if (step_lp) {
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLW: Found step lwp %s.\n",
- target_pid_to_str (lp->ptid));
- ptid = lp->ptid;
- pid = PIDGET (ptid);
+ target_pid_to_str (step_lp->ptid));
}
/* If any pid, check if there is a LWP with a wait status pending. */
@@ -2161,8 +2168,9 @@ retry:
}
/* Make sure we don't report a SIGSTOP that we sent
- ourselves in an attempt to stop an LWP. */
- if (lp->signalled
+ ourselves in an attempt to stop an LWP, unless we
+ intentionally want to see the SIGSTOP. */
+ if (lp->signalled && !intentional_stop
&& WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
{
if (debug_linux_nat)
@@ -2196,6 +2204,20 @@ retry:
if (pid == -1)
{
+ lp = NULL;
+ if (step_lp && errno == ECHILD)
+ {
+ /* We have stepped over a thread exit. We want to stop
+ the first existing lwp we find and report a stop event. */
+ for (lp = lwp_list; lp && lp == step_lp; lp = lp->next)
+ ; /* empty */
+ }
+ if (lp != NULL)
+ {
+ stop_callback (lp, NULL);
+ intentional_stop = 1;
+ }
+
/* Alternate between checking cloned and uncloned processes. */
options ^= __WCLONE;
@@ -2268,6 +2290,42 @@ retry:
fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n",
status_to_str (status), target_pid_to_str (lp->ptid));
+ /* Check if there is any LWP that is being single-stepped. We need to
+ wait specifically on such an LWP because the higher-level code is
+ expecting a step operation to find an event on the stepped LWP.
+ It is possible for other events to occur before the step operation
+ gets the expected trap so we don't want to wait on any LWP.
+ This has ramifications when adjustment of the PC is required which can be
+ different after a breakpoint vs a step (e.g. x86). */
+ if (step_lp && step_lp != lp)
+ {
+ struct lwp_info *ptr;
+ int arg = 1;
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Found step lwp %s.\n",
+ target_pid_to_str (step_lp->ptid));
+ stop_and_resume_callback (step_lp, &arg);
+ for (ptr = lwp_list; ptr; ptr = ptr->next)
+ if (step_lp == ptr)
+ break;
+
+ if (ptr)
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Continuing step lwp %s.\n",
+ target_pid_to_str (step_lp->ptid));
+ ptid = step_lp->ptid;
+ pid = PIDGET (ptid);
+ lp->status = status;
+ status = 0;
+ options = WNOHANG | (step_lp->cloned ? __WCLONE : 0);
+ pid = GET_LWP (ptid);
+ goto retry;
+ }
+ }
+
/* Now stop all other LWP's ... */
iterate_over_lwps (stop_callback, NULL);
@@ -2306,6 +2364,10 @@ retry:
else
store_waitstatus (ourstatus, status);
+ /* If we were stepping a thread and it exited, mark this. */
+ if (step_lp && step_lp != lp)
+ ourstatus->step_thread_exit = 1;
+
return lp->ptid;
}
Index: gdb-6.5/gdb/target.h
===================================================================
--- gdb-6.5.orig/gdb/target.h 2006-07-12 01:54:29.000000000 -0300
+++ gdb-6.5/gdb/target.h 2006-07-12 03:22:40.000000000 -0300
@@ -136,6 +136,7 @@ enum target_waitkind
struct target_waitstatus
{
enum target_waitkind kind;
+ int step_thread_exit; /* non-zero if we step over a thread exit. */
/* Forked child pid, execd pathname, exit status or signal number. */
union

View File

@ -1,58 +0,0 @@
2004-12-07 Jeff Johnston <jjohnstn@redhat.com>
* linux-nat.c (find_singlestep_lwp_callback): New function.
(linux-nat-wait): Before waiting on any pid, check if there
is a stepping lwp and if so, wait on it specifically.
--- gdb-6.3/gdb/linux-nat.c.fix Tue Dec 7 19:39:34 2004
+++ gdb-6.3/gdb/linux-nat.c Tue Dec 7 19:39:46 2004
@@ -1489,9 +1489,21 @@ count_events_callback (struct lwp_info *
return 0;
}
-/* Select the LWP (if any) that is currently being single-stepped. */
+/* Find an LWP (if any) that is currently being single-stepped. */
static int
+find_singlestep_lwp_callback (struct lwp_info *lp, void *data)
+{
+ if (lp->step)
+ return 1;
+ else
+ return 0;
+}
+
+/* Select the LWP with an event (if any) that is currently being
+ single-stepped. */
+
+static int
select_singlestep_lwp_callback (struct lwp_info *lp, void *data)
{
if (lp->step && lp->status != 0)
@@ -1774,7 +1786,25 @@ retry:
least if there are any LWPs at all. */
gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
- /* First check if there is a LWP with a wait status pending. */
+ /* Check if there is any LWP that is being single-stepped. We need to
+ wait specifically on such an LWP because the higher-level code is
+ expecting a step operation to find an event on the stepped LWP.
+ It is possible for other events to occur before the step operation
+ gets the expected trap so we don't want to wait on any LWP.
+ This has ramifications when adjustment of the PC is required which can be
+ different after a breakpoint vs a step (e.g. x86). */
+ lp = iterate_over_lwps (find_singlestep_lwp_callback, NULL);
+ if (lp) {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Found step lwp %s.\n",
+ target_pid_to_str (lp->ptid));
+ ptid = lp->ptid;
+ pid = PIDGET (ptid);
+ }
+
+ /* If any pid, check if there is a LWP with a wait status pending. */
+
if (pid == -1)
{
/* Any LWP that's been resumed will do. */

View File

@ -0,0 +1,291 @@
Index: gdb-6.6/gdb/testsuite/gdb.threads/atomic-seq-threaded.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.6/gdb/testsuite/gdb.threads/atomic-seq-threaded.c 2007-06-18 20:24:04.000000000 +0200
@@ -0,0 +1,171 @@
+/* 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., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* Test stepping over RISC atomic sequences.
+ This variant testcases the code for stepping another thread while skipping
+ over the atomic sequence in the former thread
+ (STEPPING_PAST_SINGLESTEP_BREAKPOINT).
+ Code comes from gcc/testsuite/gcc.dg/sync-2.c */
+
+/* { dg-options "-march=i486" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+/* { dg-options "-mcpu=v9" { target sparc*-*-* } } */
+
+/* Test functionality of the intrinsics for 'short' and 'char'. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include <unistd.h>
+
+#define LOOPS 2
+
+static int unused;
+
+static char AI[18];
+static char init_qi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
+static char test_qi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
+
+static void
+do_qi (void)
+{
+ if (__sync_fetch_and_add(AI+4, 1) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AI+5, 4) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AI+6, 22) != 0)
+ abort ();
+ if (__sync_fetch_and_sub(AI+7, 12) != 0)
+ abort ();
+ if (__sync_fetch_and_and(AI+8, 7) != (char)-1)
+ abort ();
+ if (__sync_fetch_and_or(AI+9, 8) != 0)
+ abort ();
+ if (__sync_fetch_and_xor(AI+10, 9) != 0)
+ abort ();
+ if (__sync_fetch_and_nand(AI+11, 7) != 0)
+ abort ();
+
+ if (__sync_add_and_fetch(AI+12, 1) != 1)
+ abort ();
+ if (__sync_sub_and_fetch(AI+13, 12) != (char)-12)
+ abort ();
+ if (__sync_and_and_fetch(AI+14, 7) != 7)
+ abort ();
+ if (__sync_or_and_fetch(AI+15, 8) != 8)
+ abort ();
+ if (__sync_xor_and_fetch(AI+16, 9) != 9)
+ abort ();
+ if (__sync_nand_and_fetch(AI+17, 7) != 7)
+ abort ();
+}
+
+static short AL[18];
+static short init_hi[18] = { 3,5,7,9,0,0,0,0,-1,0,0,0,0,0,-1,0,0,0 };
+static short test_hi[18] = { 3,5,7,9,1,4,22,-12,7,8,9,7,1,-12,7,8,9,7 };
+
+static void
+do_hi (void)
+{
+ if (__sync_fetch_and_add(AL+4, 1) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AL+5, 4) != 0)
+ abort ();
+ if (__sync_fetch_and_add(AL+6, 22) != 0)
+ abort ();
+ if (__sync_fetch_and_sub(AL+7, 12) != 0)
+ abort ();
+ if (__sync_fetch_and_and(AL+8, 7) != -1)
+ abort ();
+ if (__sync_fetch_and_or(AL+9, 8) != 0)
+ abort ();
+ if (__sync_fetch_and_xor(AL+10, 9) != 0)
+ abort ();
+ if (__sync_fetch_and_nand(AL+11, 7) != 0)
+ abort ();
+
+ if (__sync_add_and_fetch(AL+12, 1) != 1)
+ abort ();
+ if (__sync_sub_and_fetch(AL+13, 12) != -12)
+ abort ();
+ if (__sync_and_and_fetch(AL+14, 7) != 7)
+ abort ();
+ if (__sync_or_and_fetch(AL+15, 8) != 8)
+ abort ();
+ if (__sync_xor_and_fetch(AL+16, 9) != 9)
+ abort ();
+ if (__sync_nand_and_fetch(AL+17, 7) != 7)
+ abort ();
+}
+
+static void *
+start1 (void *arg)
+{
+ unsigned loop;
+ sleep(1);
+
+ for (loop = 0; loop < LOOPS; loop++)
+ {
+ memcpy(AI, init_qi, sizeof(init_qi));
+
+ do_qi ();
+
+ if (memcmp (AI, test_qi, sizeof(test_qi)))
+ abort ();
+ }
+
+ return arg; /* _delete1_ */
+}
+
+static void *
+start2 (void *arg)
+{
+ unsigned loop;
+
+ for (loop = 0; loop < LOOPS; loop++)
+ {
+ memcpy(AL, init_hi, sizeof(init_hi));
+
+ do_hi ();
+
+ if (memcmp (AL, test_hi, sizeof(test_hi)))
+ abort ();
+ }
+
+ return arg; /* _delete2_ */
+}
+
+int
+main (int argc, char **argv)
+{
+ pthread_t thread;
+ int i;
+
+ i = pthread_create (&thread, NULL, start1, NULL); /* _create_ */
+ assert (i == 0); /* _create_behind_ */
+
+ sleep(1);
+
+ start2 (NULL);
+
+ i = pthread_join (thread, NULL); /* _delete_ */
+ assert (i == 0);
+
+ return 0; /* _success_ */
+}
Index: gdb-6.6/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-6.6/gdb/testsuite/gdb.threads/atomic-seq-threaded.exp 2007-06-18 20:24:04.000000000 +0200
@@ -0,0 +1,110 @@
+# atomic-seq-threaded.exp -- Test case for stepping over RISC atomic code seqs.
+# This variant testcases the code for stepping another thread while skipping
+# over the atomic sequence in the former thread
+# (STEPPING_PAST_SINGLESTEP_BREAKPOINT).
+# Copyright (C) 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. */
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+set testfile atomic-seq-threaded
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+foreach opts {{} {compiler=gcc4} {FAIL}} {
+ if {$opts eq "FAIL"} {
+ return -1
+ }
+ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $opts]] eq "" } {
+ break
+ }
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_load ${binfile}
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 0
+}
+
+# pthread_create () will not pass even on x86_64 with software watchpoint.
+# Skip behind pthread_create () without any watchpoint active.
+
+set line [gdb_get_line_number "_create_behind_"]
+gdb_test "tbreak $line" \
+ "Breakpoint (\[0-9\]+) at .*$srcfile, line $line\..*" \
+ "set breakpoint behind pthread_create ()"
+gdb_test "c" \
+ ".*/\\* _create_behind_ \\*/.*" \
+ "run till behind pthread_create ()"
+
+# Without a watchpoint being software no single-stepping would be used.
+set test "Start (software) watchpoint"
+gdb_test_multiple "watch unused" $test {
+ -re "Watchpoint \[0-9\]+: unused.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "Hardware watchpoint \[0-9\]+: unused.*$gdb_prompt $" {
+ # We do not test the goal but still the whole testcase should pass.
+ unsupported $test
+ }
+}
+gdb_test "set \$watchnum=\$bpnum" "" "Store the watchpoint number"
+
+# pthread_join () will not pass even on x86_64 with software watchpoint.
+# Now pass the __sync_* () functions and remove the watchpoint.
+
+#set line [gdb_get_line_number "_delete_"]
+#gdb_test "break $line" \
+# "Breakpoint \[0-9\]+ at .*$srcfile, line $line\..*" \
+# "set breakpoint at _delete_"
+#gdb_test "set \$deletenum=\$bpnum" "" "Store the _delete_ breakpoint number"
+#set line1 [gdb_get_line_number "_delete1_"]
+#gdb_test "break $line1" \
+# "Breakpoint \[0-9\]+ at .*$srcfile, line $line1\..*" \
+# "set breakpoint at _delete1_"
+#gdb_test "set \$delete1num=\$bpnum" "" "Store the _delete1_ breakpoint number"
+#set line2 [gdb_get_line_number "_delete2_"]
+#gdb_test "break $line2" \
+# "Breakpoint \[0-9\]+ at .*$srcfile, line $line2\..*" \
+# "set breakpoint at _delete2_"
+#gdb_test "set \$delete2num=\$bpnum" "" "Store the _delete2_ breakpoint number"
+#gdb_test "c" \
+# ".*/\\* (_delete_|_delete1_|_delete2_) \\*/.*" \
+# "run till (_delete_|_delete1_|_delete2_)"
+#gdb_test "delete \$watchnum" "" "Delete the watchpoint"
+#gdb_test "delete \$deletenum" "" "Delete the _delete_ breakpoint"
+#gdb_test "delete \$delete1num" "" "Delete the _delete1_ breakpoint"
+#gdb_test "delete \$delete2num" "" "Delete the _delete2_ breakpoint"
+
+# Pass pthread_join () without the software watchpoint being active.
+
+set line [gdb_get_line_number "_success_"]
+gdb_test "tbreak $line" \
+ "Breakpoint \[0-9\]+ at .*$srcfile, line $line\..*" \
+ "set breakpoint at _success_"
+set timeout 1800
+gdb_test "c" \
+ ".*/\\* _success_ \\*/.*" \
+ "run till _success_"
+
+gdb_test "c" \
+ ".*Program exited normally\\..*" \
+ "run till program exit"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,160 @@
Index: ./gdb/inferior.h
===================================================================
RCS file: /cvs/src/src/gdb/inferior.h,v
retrieving revision 1.83
diff -u -p -r1.83 inferior.h
--- ./gdb/inferior.h 15 Jun 2007 22:44:55 -0000 1.83
+++ ./gdb/inferior.h 19 Jun 2007 07:14:04 -0000
@@ -194,7 +194,15 @@ extern void reopen_exec_file (void);
/* The `resume' routine should only be called in special circumstances.
Normally, use `proceed', which handles a lot of bookkeeping. */
-extern void resume (int, enum target_signal);
+enum resume_step
+ {
+ /* currently_stepping () should return non-zero for non-continue. */
+ RESUME_STEP_CONTINUE = 0,
+ RESUME_STEP_USER, /* Stepping is intentional by the user. */
+ RESUME_STEP_NEEDED /* Stepping only for software watchpoints. */
+ };
+
+extern void resume (enum resume_step, enum target_signal);
/* From misc files */
Index: ./gdb/infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.241
diff -u -p -r1.241 infrun.c
--- ./gdb/infrun.c 18 Jun 2007 18:23:08 -0000 1.241
+++ ./gdb/infrun.c 19 Jun 2007 07:14:32 -0000
@@ -76,7 +76,8 @@ static void set_schedlock_func (char *ar
struct execution_control_state;
-static int currently_stepping (struct execution_control_state *ecs);
+static enum resume_step currently_stepping (struct execution_control_state
+ *ecs);
static void xdb_handle_command (char *args, int from_tty);
@@ -466,7 +467,7 @@ static const char *scheduler_enums[] = {
schedlock_step,
NULL
};
-static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_mode = schedlock_step;
static void
show_scheduler_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -496,15 +497,18 @@ set_schedlock_func (char *args, int from
STEP nonzero if we should step (zero to continue instead).
SIG is the signal to give the inferior (zero for none). */
void
-resume (int step, enum target_signal sig)
+resume (enum resume_step step, enum target_signal sig)
{
int should_resume = 1;
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
QUIT;
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
- step, sig);
+ fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%s, signal=%d)\n",
+ (step == RESUME_STEP_CONTINUE ? "RESUME_STEP_CONTINUE"
+ : (step == RESUME_STEP_USER ? "RESUME_STEP_USER"
+ : "RESUME_STEP_NEEDED")),
+ sig);
/* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
@@ -595,7 +599,8 @@ a command like `return' or `jump' to con
if ((scheduler_mode == schedlock_on)
|| (scheduler_mode == schedlock_step
- && (step || singlestep_breakpoints_inserted_p)))
+ && (step == RESUME_STEP_USER
+ || singlestep_breakpoints_inserted_p)))
{
/* User-settable 'scheduler' mode requires solo thread resume. */
resume_ptid = inferior_ptid;
@@ -705,7 +710,8 @@ static CORE_ADDR prev_pc;
void
proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
{
- int oneproc = 0;
+ enum resume_step resume_step = (step ? RESUME_STEP_USER
+ : RESUME_STEP_CONTINUE);
if (step > 0)
step_start_function = find_pc_function (read_pc ());
@@ -719,13 +725,13 @@ proceed (CORE_ADDR addr, enum target_sig
step one instruction before inserting breakpoints so that
we do not stop right away (and report a second hit at this
breakpoint). */
- oneproc = 1;
+ resume_step = RESUME_STEP_USER;
else if (gdbarch_single_step_through_delay_p (current_gdbarch)
&& gdbarch_single_step_through_delay (current_gdbarch,
get_current_frame ()))
/* We stepped onto an instruction that needs to be stepped
again before re-inserting the breakpoint, do so. */
- oneproc = 1;
+ resume_step = RESUME_STEP_USER;
}
else
{
@@ -749,9 +755,9 @@ proceed (CORE_ADDR addr, enum target_sig
that reported the most recent event. If a step-over is required
it returns TRUE and sets the current thread to the old thread. */
if (prepare_to_proceed () && breakpoint_here_p (read_pc ()))
- oneproc = 1;
+ resume_step = RESUME_STEP_USER;
- if (oneproc)
+ if (resume_step == RESUME_STEP_USER)
/* We will get a trace trap after one instruction.
Continue it automatically and insert breakpoints then. */
trap_expected = 1;
@@ -800,8 +806,11 @@ proceed (CORE_ADDR addr, enum target_sig
updated correctly when the inferior is stopped. */
prev_pc = read_pc ();
+ if (resume_step == RESUME_STEP_CONTINUE && bpstat_should_step ())
+ resume_step = RESUME_STEP_NEEDED;
+
/* Resume inferior. */
- resume (oneproc || step || bpstat_should_step (), stop_signal);
+ resume (resume_step, stop_signal);
/* Wait for it to stop (if not standalone)
and in any case decode why it stopped, and act accordingly. */
@@ -2695,14 +2704,20 @@ process_event_stop_test:
/* Are we in the middle of stepping? */
-static int
+static enum resume_step
currently_stepping (struct execution_control_state *ecs)
{
- return ((!ecs->handling_longjmp
- && ((step_range_end && step_resume_breakpoint == NULL)
- || trap_expected))
- || ecs->stepping_through_solib_after_catch
- || bpstat_should_step ());
+ if (!ecs->handling_longjmp
+ && ((step_range_end && step_resume_breakpoint == NULL) || trap_expected))
+ return RESUME_STEP_USER;
+
+ if (ecs->stepping_through_solib_after_catch)
+ return RESUME_STEP_USER;
+
+ if (bpstat_should_step ())
+ return RESUME_STEP_NEEDED;
+
+ return RESUME_STEP_CONTINUE;
}
/* Subroutine call with source code we should not step over. Do step

View File

@ -0,0 +1,80 @@
Index: ./gdb/linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.64
diff -u -p -r1.64 linux-nat.c
--- ./gdb/linux-nat.c 16 Jun 2007 17:16:25 -0000 1.64
+++ ./gdb/linux-nat.c 18 Jun 2007 12:53:41 -0000
@@ -1109,15 +1109,17 @@ resume_set_callback (struct lwp_info *lp
}
static void
-linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
+linux_nat_resume (ptid_t ptid, int step_int, enum target_signal signo)
{
struct lwp_info *lp;
int resume_all;
+ enum resume_step step = step_int;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LLR: Preparing to %s %s, %s, inferior_ptid %s\n",
- step ? "step" : "resume",
+ (step == RESUME_STEP_NEEDED
+ ? "needed" : (step ? "step" : "resume")),
target_pid_to_str (ptid),
signo ? strsignal (signo) : "0",
target_pid_to_str (inferior_ptid));
@@ -2077,6 +2082,9 @@ retry:
/* Check if the thread has exited. */
if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
{
+ enum resume_step step = lp->step;
+ pid_t pid = GET_PID (lp->ptid);
+
/* If this is the main thread, we must stop all threads and
verify if they are still alive. This is because in the nptl
thread model, there is no signal issued for exiting LWPs
@@ -2095,6 +2103,10 @@ retry:
fprintf_unfiltered (gdb_stdlog,
"LLW: %s exited.\n",
target_pid_to_str (lp->ptid));
+ /* Backward compatibility with:
+ gdb-6.3-step-thread-exit-20050211.patch */
+ if (step == RESUME_STEP_USER)
+ printf_unfiltered ("[Stepped over thread exit]\n");
exit_lwp (lp);
@@ -2105,8 +2117,29 @@ retry:
ignored. */
if (num_lwps > 0)
{
- /* Make sure there is at least one thread running. */
- gdb_assert (iterate_over_lwps (running_callback, NULL));
+ if (step == RESUME_STEP_USER)
+ {
+ /* Now stop the closest LWP's ... */
+ lp = find_lwp_pid (pid_to_ptid (pid));
+ if (!lp)
+ lp = lwp_list;
+ errno = 0;
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0,
+ (void *) (unsigned long) SIGSTOP);
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "PTRACE_CONT %s, 0, 0 (%s)\n",
+ target_pid_to_str (lp->ptid),
+ errno ? safe_strerror (errno)
+ : "OK");
+ /* Avoid the silent `delayed SIGSTOP' handling. */
+ lp->signalled = 0;
+ }
+ else
+ {
+ /* Make sure there is at least one thread running. */
+ gdb_assert (iterate_over_lwps (running_callback, NULL));
+ }
/* Discard the event. */
status = 0;

View File

@ -11,7 +11,7 @@ Name: gdb
Version: 6.6
# The release always contains a leading reserved number, start it at 1.
Release: 16%{?dist}
Release: 17%{?dist}
License: GPL
Group: Development/Debuggers
@ -74,8 +74,9 @@ Patch108: gdb-6.3-ppc64section-20041026.patch
# correct symbol is found.
Patch111: gdb-6.3-ppc64displaysymbol-20041124.patch
# Fix stepping in threads
Patch112: gdb-6.3-thread-step-20041207.patch
# Use upstream `set scheduler-locking step' as default.
# Fix upstream `set scheduler-locking step' vs. upstream PPC atomic seqs.
Patch112: gdb-6.6-scheduler_locking-step-sw-watchpoints2.patch
# Threaded watchpoint support
Patch113: gdb-6.3-threaded-watchpoints-20041213.patch
@ -128,8 +129,9 @@ Patch139: gdb-6.3-dwattype0-20050201.patch
# Fix gcore for threads
Patch140: gdb-6.3-gcore-thread-20050204.patch
# Fix stepping over thread exit
Patch141: gdb-6.3-step-thread-exit-20050211.patch
# Stop while intentionally stepping and the thread exit is met.
Patch141: gdb-6.6-step-thread-exit.patch
Patch259: gdb-6.3-step-thread-exit-20050211-test.patch
# Prevent gdb from being pushed into background
Patch142: gdb-6.3-terminal-fix-20050214.patch
@ -350,6 +352,10 @@ Patch254: gdb-6.6-testsuite-timeouts.patch
# Fix attaching during a pending signal being delivered.
Patch256: gdb-6.6-bz233852-attach-signalled.patch
# Support for stepping over PPC atomic instruction sequences (BZ 237572).
Patch257: gdb-6.6-bz237572-ppc-atomic-sequence-upstream.patch
Patch258: gdb-6.6-bz237572-ppc-atomic-sequence-test.patch
BuildRequires: ncurses-devel glibc-devel gcc make gzip texinfo dejagnu gettext
BuildRequires: flex bison sharutils expat-devel
@ -418,6 +424,7 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c
%patch139 -p1
%patch140 -p1
%patch141 -p1
%patch259 -p1
%patch142 -p1
%patch145 -p1
%patch147 -p1
@ -494,6 +501,8 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c
%patch251 -p1
%patch254 -p1
%patch256 -p1
%patch257 -p1
%patch258 -p1
# Change the version that gets printed at GDB startup, so it is RedHat
# specific.
@ -643,6 +652,10 @@ fi
# don't include the files in include, they are part of binutils
%changelog
* Thu Jun 21 2007 Jan Kratochvil <jan.kratochvil@redhat.com> - 6.6-17
- Support for stepping over PPC atomic instruction sequences (BZ 237572).
- `set scheduler-locking step' is no longer enforced but it is now default.
* 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.