Fix gdbserver regression exposed by gdb.threads/multi-create-ns-info-thr.exp

Commit 8629910955 ("Add thread_db_notice_clone to gdbserver")
introduced calls into libthread_db without making sure that the
current thread is pointing to a know-stopped thread.  This resulted in
sometimes thread_db_notice_clone failing->find_one_thread failing like
this, as seen when running gdb.threads/multi-create-ns-info-thr.exp:

~~~
  Thread <6> executing
  Thread <7> executing
  gdbserver: PID mismatch!  Expected 27472, got 27471
  gdbserver: Cannot find thread after clone.

  Thread <1000> executing
  Thread <1001> executing
~~~

Things go south from here and sometimes that ends up resulting in
gdbserver crashing and the test failing.

gdb/gdbserver/ChangeLog:
2017-09-29  Pedro Alves  <palves@redhat.com>

	* linux-low.c (handle_extended_wait): Pass parent thread instead
	of process to thread_db_notice_clone.
	* linux-low.h (thread_db_notice_clone): Replace parent process
	parameter with parent thread parameter.
	* thread-db.c (find_one_thread): Add comment.
	(thread_db_notice_clone): Replace parent process parameter with
	parent thread parameter.  Temporarily switch to the parent thread.
This commit is contained in:
Pedro Alves 2017-09-29 13:06:34 +01:00
parent f6ac8c52c9
commit 94c207e097
4 changed files with 26 additions and 5 deletions

View File

@ -1,3 +1,13 @@
2017-09-29 Pedro Alves <palves@redhat.com>
* linux-low.c (handle_extended_wait): Pass parent thread instead
of process to thread_db_notice_clone.
* linux-low.h (thread_db_notice_clone): Replace parent process
parameter with parent thread parameter.
* thread-db.c (find_one_thread): Add comment.
(thread_db_notice_clone): Replace parent process parameter with
parent thread parameter. Temporarily switch to the parent thread.
2017-09-26 Sergio Durigan Junior <sergiodj@redhat.com> 2017-09-26 Sergio Durigan Junior <sergiodj@redhat.com>
* gdbthread.h: Include "common-gdbthread.h". * gdbthread.h: Include "common-gdbthread.h".

View File

@ -656,7 +656,7 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat)
new_lwp->status_pending = status; new_lwp->status_pending = status;
} }
thread_db_notice_clone (get_thread_process (event_thr), ptid); thread_db_notice_clone (event_thr, ptid);
/* Don't report the event. */ /* Don't report the event. */
return 1; return 1;

View File

@ -417,7 +417,7 @@ int thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp);
both the clone and the parent should be stopped. This function does both the clone and the parent should be stopped. This function does
whatever is required have the clone under thread_db's control. */ whatever is required have the clone under thread_db's control. */
void thread_db_notice_clone (struct process_info *proc, ptid_t lwp); void thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid);
bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len); bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len);

View File

@ -28,6 +28,7 @@ extern int debug_threads;
#include "nat/gdb_thread_db.h" #include "nat/gdb_thread_db.h"
#include "gdb_vecs.h" #include "gdb_vecs.h"
#include "nat/linux-procfs.h" #include "nat/linux-procfs.h"
#include "common/scoped_restore.h"
#ifndef USE_LIBTHREAD_DB_DIRECTLY #ifndef USE_LIBTHREAD_DB_DIRECTLY
#include <dlfcn.h> #include <dlfcn.h>
@ -155,6 +156,9 @@ thread_db_state_str (td_thr_state_e state)
} }
#endif #endif
/* Get thread info about PTID, accessing memory via the current
thread. */
static int static int
find_one_thread (ptid_t ptid) find_one_thread (ptid_t ptid)
{ {
@ -887,15 +891,22 @@ thread_db_handle_monitor_command (char *mon)
/* See linux-low.h. */ /* See linux-low.h. */
void void
thread_db_notice_clone (struct process_info *proc, ptid_t ptid) thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid)
{ {
struct thread_db *thread_db = proc->priv->thread_db; process_info *parent_proc = get_thread_process (parent_thr);
struct thread_db *thread_db = parent_proc->priv->thread_db;
/* If the thread layer isn't initialized, return. It may just /* If the thread layer isn't initialized, return. It may just
be that the program uses clone, but does not use libthread_db. */ be that the program uses clone, but does not use libthread_db. */
if (thread_db == NULL || !thread_db->all_symbols_looked_up) if (thread_db == NULL || !thread_db->all_symbols_looked_up)
return; return;
if (!find_one_thread (ptid)) /* find_one_thread calls into libthread_db which accesses memory via
the current thread. Temporarily switch to a thread we know is
stopped. */
scoped_restore restore_current_thread
= make_scoped_restore (&current_thread, parent_thr);
if (!find_one_thread (child_ptid))
warning ("Cannot find thread after clone.\n"); warning ("Cannot find thread after clone.\n");
} }