diff options
author | Pedro Alves <palves@redhat.com> | 2014-12-16 16:12:24 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2015-01-09 11:41:01 +0000 |
commit | a33e39599ce39ec6225d71f7da1719b544740745 (patch) | |
tree | 6ae0a75c900c6f95e33ff3285b3912cd512863da | |
parent | 8784d56326e72e2e6863e8443b1f97e45a46ba36 (diff) | |
download | gdb-a33e39599ce39ec6225d71f7da1719b544740745.zip gdb-a33e39599ce39ec6225d71f7da1719b544740745.tar.gz gdb-a33e39599ce39ec6225d71f7da1719b544740745.tar.bz2 |
libthread_db: Skip attaching to terminated and joined threads
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On GNU/Linux, attaching to a multi-threaded program sometimes prints
out warnings like:
...
[New LWP 20700]
warning: unable to open /proc file '/proc/-1/status'
[New LWP 20850]
[New LWP 21019]
...
That happens because when a thread exits, and is joined, glibc does:
nptl/pthread_join.c:
pthread_join ()
{
...
if (__glibc_likely (result == 0))
{
/* We mark the thread as terminated and as joined. */
pd->tid = -1;
...
/* Free the TCB. */
__free_tcb (pd);
}
So if we attach or interrupt the program (which does an implicit "info
threads") at just the right (or rather, wrong) time, we can find and
return threads in the libthread_db/pthreads thread list with kernel
thread ID -1. I've filed glibc PR nptl/17707 for this. You'll find
more info there.
This patch handles this as a special case in GDB.
This is actually more than just a cosmetic issue. lin_lwp_attach_lwp
will think that this -1 is an LWP we're not attached to yet, and after
failing to attach will try to check we were already attached to the
process, using a waitpid call, which in this case ends up being
"waitpid (-1, ...", which obviously results in GDB potentially
discarding an event when it shouldn't...
Tested on x86_64 Fedora 20, native and gdbserver.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* thread-db.c (find_new_threads_callback): Ignore thread if the
kernel thread ID is -1.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're
about to wait for is > 0.
* linux-thread-db.c (find_new_threads_callback): Ignore thread if
the kernel thread ID is -1.
-rw-r--r-- | gdb/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/gdbserver/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/gdbserver/thread-db.c | 11 | ||||
-rw-r--r-- | gdb/linux-nat.c | 1 | ||||
-rw-r--r-- | gdb/linux-thread-db.c | 11 |
5 files changed, 35 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4ee17b3..fb99d26 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,12 @@ 2015-01-09 Pedro Alves <palves@redhat.com> + * linux-nat.c (lin_lwp_attach_lwp): Assert that the lwp id we're + about to wait for is > 0. + * linux-thread-db.c (find_new_threads_callback): Ignore thread if + the kernel thread ID is -1. + +2015-01-09 Pedro Alves <palves@redhat.com> + * linux-nat.c (attach_proc_task_lwp_callback): New function. (linux_nat_attach): Use linux_proc_attach_tgid_threads. (wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 2ee6a00..d6bafae 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,10 @@ 2015-01-09 Pedro Alves <palves@redhat.com> + * thread-db.c (find_new_threads_callback): Ignore thread if the + kernel thread ID is -1. + +2015-01-09 Pedro Alves <palves@redhat.com> + * linux-low.c (linux_attach_fail_reason_string): Move to nat/linux-ptrace.c, and rename. (linux_attach_lwp): Update comment. diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 4e0d32a..b0d1f0d 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -396,6 +396,17 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) if (err != TD_OK) error ("Cannot get thread info: %s", thread_db_err_str (err)); + if (ti.ti_lid == -1) + { + /* A thread with kernel thread ID -1 is either a thread that + exited and was joined, or a thread that is being created but + hasn't started yet, and that is reusing the tcb/stack of a + thread that previously exited and was joined. (glibc marks + terminated and joined threads with kernel thread ID -1. See + glibc PR17707. */ + return 0; + } + /* Check for zombies. */ if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) return 0; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 0adf3a9..77aa8e3 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1023,6 +1023,7 @@ lin_lwp_attach_lwp (ptid_t ptid) /* See if we've got a stop for this new child pending. If so, we're already attached. */ + gdb_assert (lwpid > 0); new_pid = my_waitpid (lwpid, &status, WNOHANG); if (new_pid == -1 && errno == ECHILD) new_pid = my_waitpid (lwpid, &status, __WCLONE | WNOHANG); diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index b7afb03..1417542 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -1610,6 +1610,17 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data) error (_("find_new_threads_callback: cannot get thread info: %s"), thread_db_err_str (err)); + if (ti.ti_lid == -1) + { + /* A thread with kernel thread ID -1 is either a thread that + exited and was joined, or a thread that is being created but + hasn't started yet, and that is reusing the tcb/stack of a + thread that previously exited and was joined. (glibc marks + terminated and joined threads with kernel thread ID -1. See + glibc PR17707. */ + return 0; + } + if (ti.ti_tid == 0) { /* A thread ID of zero means that this is the main thread, but |