aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-06-19 11:59:03 +0100
committerPedro Alves <palves@redhat.com>2014-06-19 11:59:03 +0100
commit034f788c5ec1e5b20fae3b6efc7fe961631e014d (patch)
tree039c2ea366839afb8a82d98df115b5c60f8ad80d
parent46e3325277e604face2848eec78247826b94d5c9 (diff)
downloadgdb-034f788c5ec1e5b20fae3b6efc7fe961631e014d.zip
gdb-034f788c5ec1e5b20fae3b6efc7fe961631e014d.tar.gz
gdb-034f788c5ec1e5b20fae3b6efc7fe961631e014d.tar.bz2
Fix next over threaded execl with "set scheduler-locking step".
Running gdb.threads/thread-execl.exp with scheduler-locking set to "step" reveals a problem: (gdb) next^M [Thread 0x7ffff7fda700 (LWP 27168) exited]^M [New LWP 27168]^M [Thread 0x7ffff74ee700 (LWP 27174) exited]^M process 27168 is executing new program: /home/jkratoch/redhat/gdb-clean/gdb/testsuite/gdb.threads/thread-execl^M [Thread debugging using libthread_db enabled]^M Using host libthread_db library "/lib64/libthread_db.so.1".^M infrun.c:5225: internal-error: switch_back_to_stepped_thread: Assertion `!schedlock_applies (1)' failed.^M A problem internal to GDB has been detected,^M further debugging may prove unreliable.^M Quit this debugging session? (y or n) FAIL: gdb.threads/thread-execl.exp: schedlock step: get to main in new image (GDB internal error) The assertion is correct. The issue is that GDB is mistakenly trying to switch back to an exited thread, that was previously stepping when it exited. This is exactly the sort of thing the test wants to make sure doesn't happen: # Now set a breakpoint at `main', and step over the execl call. The # breakpoint at main should be reached. GDB should not try to revert # back to the old thread from the old image and resume stepping it We don't see this bug with schedlock off only because a different sequence of events makes GDB manage to delete the thread instead of marking it exited. This particular internal error can be fixed by making the loop over all threads in switch_back_to_stepped_thread skip exited threads. But, looking over other ALL_THREADS users, all either can or should be skipping exited threads too. So for simplicity, this patch replaces ALL_THREADS with a new macro that skips exited threads itself, and updates everything to use it. Tested on x86_64 Fedora 20. gdb/ 2014-06-19 Pedro Alves <palves@redhat.com> * gdbthread.h (ALL_THREADS): Delete. (ALL_NON_EXITED_THREADS): New macro. * btrace.c (btrace_free_objfile): Use ALL_NON_EXITED_THREADS instead of ALL_THREADS. * infrun.c (find_thread_needs_step_over) (switch_back_to_stepped_thread): Use ALL_NON_EXITED_THREADS instead of ALL_THREADS. * record-btrace.c (record_btrace_open) (record_btrace_stop_recording, record_btrace_close) (record_btrace_is_replaying, record_btrace_resume) (record_btrace_find_thread_to_move, record_btrace_wait): Likewise. * remote.c (append_pending_thread_resumptions): Likewise. * thread.c (thread_apply_all_command): Likewise. gdb/testsuite/ 2014-06-19 Pedro Alves <palves@redhat.com> * gdb.threads/thread-execl.exp (do_test): New procedure, factored out from ... (top level): ... here. Iterate running tests under different scheduler-locking settings.
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/btrace.c2
-rw-r--r--gdb/gdbthread.h8
-rw-r--r--gdb/infrun.c4
-rw-r--r--gdb/record-btrace.c14
-rw-r--r--gdb/remote.c2
-rw-r--r--gdb/testsuite/ChangeLog7
-rw-r--r--gdb/testsuite/gdb.threads/thread-execl.exp44
-rw-r--r--gdb/thread.c2
9 files changed, 69 insertions, 30 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f13c19a..850b267 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,19 @@
+2014-06-19 Pedro Alves <palves@redhat.com>
+
+ * gdbthread.h (ALL_THREADS): Delete.
+ (ALL_NON_EXITED_THREADS): New macro.
+ * btrace.c (btrace_free_objfile): Use ALL_NON_EXITED_THREADS
+ instead of ALL_THREADS.
+ * infrun.c (find_thread_needs_step_over)
+ (switch_back_to_stepped_thread): Use ALL_NON_EXITED_THREADS
+ instead of ALL_THREADS.
+ * record-btrace.c (record_btrace_open)
+ (record_btrace_stop_recording, record_btrace_close)
+ (record_btrace_is_replaying, record_btrace_resume)
+ (record_btrace_find_thread_to_move, record_btrace_wait): Likewise.
+ * remote.c (append_pending_thread_resumptions): Likewise.
+ * thread.c (thread_apply_all_command): Likewise.
+
2014-06-19 Gary Benson <gbenson@redhat.com>
* i386-nat.c (i386_stopped_by_watchpoint):
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 601eb41..87a171e 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -958,7 +958,7 @@ btrace_free_objfile (struct objfile *objfile)
DEBUG ("free objfile");
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
btrace_clear (tp);
}
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 9f5dee6..64e37c3 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -317,10 +317,12 @@ void thread_change_ptid (ptid_t old_ptid, ptid_t new_ptid);
typedef int (*thread_callback_func) (struct thread_info *, void *);
extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
-/* Traverse all threads. */
+/* Traverse all threads, except those that have THREAD_EXITED
+ state. */
-#define ALL_THREADS(T) \
- for (T = thread_list; T; T = T->next)
+#define ALL_NON_EXITED_THREADS(T) \
+ for (T = thread_list; T; T = T->next) \
+ if ((T)->state != THREAD_EXITED)
extern int thread_count (void);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2be2e5e..bef69a8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2160,7 +2160,7 @@ find_thread_needs_step_over (int step, struct thread_info *except)
return NULL;
}
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
{
/* Ignore the EXCEPT thread. */
if (tp == except)
@@ -5204,7 +5204,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs)
step/next/etc. */
stepping_thread = NULL;
step_over = NULL;
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
{
/* Ignore threads of processes we're not resuming. */
if (!sched_multi
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index e0c537a8..6a9bfe1 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -206,7 +206,7 @@ record_btrace_open (char *args, int from_tty)
gdb_assert (record_btrace_thread_observer == NULL);
disable_chain = make_cleanup (null_cleanup, NULL);
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
{
btrace_enable (tp);
@@ -238,7 +238,7 @@ record_btrace_stop_recording (struct target_ops *self)
record_btrace_auto_disable ();
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
if (tp->btrace.target != NULL)
btrace_disable (tp);
}
@@ -259,7 +259,7 @@ record_btrace_close (struct target_ops *self)
/* We should have already stopped recording.
Tear down btrace in case we have not. */
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
btrace_teardown (tp);
}
@@ -835,7 +835,7 @@ record_btrace_is_replaying (struct target_ops *self)
{
struct thread_info *tp;
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
if (btrace_is_replaying (tp))
return 1;
@@ -1522,7 +1522,7 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
/* Stop replaying other threads if the thread to resume is not replaying. */
if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
- ALL_THREADS (other)
+ ALL_NON_EXITED_THREADS (other)
record_btrace_stop_replaying (other);
/* As long as we're not replaying, just forward the request. */
@@ -1572,7 +1572,7 @@ record_btrace_find_thread_to_move (ptid_t ptid)
return tp;
/* Otherwise, find one other thread that has been resumed. */
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
if ((tp->btrace.flags & BTHR_MOVE) != 0)
return tp;
@@ -1777,7 +1777,7 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
/* Stop all other threads. */
if (!non_stop)
- ALL_THREADS (other)
+ ALL_NON_EXITED_THREADS (other)
other->btrace.flags &= ~BTHR_MOVE;
/* Start record histories anew from the current position. */
diff --git a/gdb/remote.c b/gdb/remote.c
index 6915dd8..b5318f1 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4626,7 +4626,7 @@ append_pending_thread_resumptions (char *p, char *endp, ptid_t ptid)
{
struct thread_info *thread;
- ALL_THREADS (thread)
+ ALL_NON_EXITED_THREADS (thread)
if (ptid_match (thread->ptid, ptid)
&& !ptid_equal (inferior_ptid, thread->ptid)
&& thread->suspend.stop_signal != GDB_SIGNAL_0
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 2fdcbb4..af37409 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2014-06-19 Pedro Alves <palves@redhat.com>
+
+ * gdb.threads/thread-execl.exp (do_test): New procedure, factored
+ out from ...
+ (top level): ... here. Iterate running tests under different
+ scheduler-locking settings.
+
2014-06-18 Luis Machado <lgustavo@codesourcery.com>
* gdb.cp/nsalias.exp: Set type of low_pc and high_pc entries
diff --git a/gdb/testsuite/gdb.threads/thread-execl.exp b/gdb/testsuite/gdb.threads/thread-execl.exp
index d837fe4..14b96d2 100644
--- a/gdb/testsuite/gdb.threads/thread-execl.exp
+++ b/gdb/testsuite/gdb.threads/thread-execl.exp
@@ -28,19 +28,33 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
return -1
}
-clean_restart ${binfile}
-
-runto_main
-
-# Get ourselves to the thread that execs
-gdb_breakpoint "thread_execler"
-gdb_test "continue" ".*thread_execler.*" "continue to thread start"
-
-# Now set a breakpoint at `main', and step over the execl call. The
-# breakpoint at main should be reached. GDB should not try to revert
-# back to the old thread from the old image and resume stepping it
-# (since it is gone).
-gdb_breakpoint "main"
-gdb_test "next" ".*main.*" "get to main in new image"
+# Run the test proper. SCHEDLOCK specifies what scheduler-locking
+# should be set to.
+
+proc do_test { schedlock } {
+ global binfile
+
+ with_test_prefix "schedlock $schedlock" {
+ clean_restart ${binfile}
+
+ if ![runto_main] {
+ return 0
+ }
+
+ # Get ourselves to the thread that execs.
+ gdb_breakpoint "thread_execler"
+ gdb_test "continue" ".*thread_execler.*" "continue to thread start"
+
+ # Now set a breakpoint at `main', and step over the execl call. The
+ # breakpoint at main should be reached. GDB should not try to revert
+ # back to the old thread from the old image and resume stepping it
+ # (since it is gone).
+ gdb_breakpoint "main"
+ gdb_test_no_output "set scheduler-locking $schedlock"
+ gdb_test "next" ".*main.*" "get to main in new image"
+ }
+}
-return 0
+foreach schedlock {"off" "step" "on"} {
+ do_test $schedlock
+}
diff --git a/gdb/thread.c b/gdb/thread.c
index 7bc5271..532149d 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1243,7 +1243,7 @@ thread_apply_all_command (char *cmd, int from_tty)
ta_cleanup.tp_array = tp_array;
ta_cleanup.count = tc;
- ALL_THREADS (tp)
+ ALL_NON_EXITED_THREADS (tp)
{
tp_array[i] = tp;
tp->refcount++;