diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index c9e21576dd..28ff0e1ac9 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,11 @@ +2015-11-30 Pedro Alves + + * gdbthread.h (find_any_thread_of_pid): Declare. + * inferiors.c (thread_of_pid, find_any_thread_of_pid): New + functions. + * server.c (handle_query): If current_thread is NULL, look for + another thread of the selected process. + 2015-11-26 Daniel Colascione Simon Marchi diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h index d6959f46e6..0510419485 100644 --- a/gdb/gdbserver/gdbthread.h +++ b/gdb/gdbserver/gdbthread.h @@ -80,6 +80,10 @@ struct thread_info *get_first_thread (void); struct thread_info *find_thread_ptid (ptid_t ptid); +/* Find any thread of the PID process. Returns NULL if none is + found. */ +struct thread_info *find_any_thread_of_pid (int pid); + /* Get current thread ID (Linux task ID). */ #define current_ptid (current_thread->entry.id) diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 72a3ef1b1b..95f3ad03ab 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -162,6 +162,29 @@ find_thread_process (const struct process_info *const process) find_inferior (&all_threads, thread_pid_matches_callback, &pid); } +/* Helper for find_any_thread_of_pid. Returns true if a thread + matches a PID. */ + +static int +thread_of_pid (struct inferior_list_entry *entry, void *pid_p) +{ + int pid = *(int *) pid_p; + + return (ptid_get_pid (entry->id) == pid); +} + +/* See gdbthread.h. */ + +struct thread_info * +find_any_thread_of_pid (int pid) +{ + struct inferior_list_entry *entry; + + entry = find_inferior (&all_threads, thread_of_pid, &pid); + + return (struct thread_info *) entry; +} + ptid_t gdb_id_to_thread_id (ptid_t gdb_id) { diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 0105b994fb..9d65f6520d 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1975,6 +1975,28 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (strcmp ("qSymbol::", own_buf) == 0) { + struct thread_info *save_thread = current_thread; + + /* For qSymbol, GDB only changes the current thread if the + previous current thread was of a different process. So if + the previous thread is gone, we need to pick another one of + the same process. This can happen e.g., if we followed an + exec in a non-leader thread. */ + if (current_thread == NULL) + { + current_thread + = find_any_thread_of_pid (ptid_get_pid (general_thread)); + + /* Just in case, if we didn't find a thread, then bail out + instead of crashing. */ + if (current_thread == NULL) + { + write_enn (own_buf); + current_thread = save_thread; + return; + } + } + /* GDB is suggesting new symbols have been loaded. This may mean a new shared library has been detected as loaded, so take the opportunity to check if breakpoints we think are @@ -1993,6 +2015,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (current_thread != NULL && the_target->look_up_symbols != NULL) (*the_target->look_up_symbols) (); + current_thread = save_thread; + strcpy (own_buf, "OK"); return; }