diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 45ca98dd28..bf911b2e59 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,51 @@ +2014-02-19 Doug Evans + + * dll.c (clear_dlls): Replace accessing list implemention details + with API function. + * gdbthread.h (get_first_thread): Declare. + * inferiors.c (for_each_inferior_with_data): New function. + (get_first_thread): New function. + (find_thread_ptid): Simplify. + (get_first_inferior): New function. + (clear_list): Delete. + (one_inferior_p): New function. + (clear_inferior_list): New function. + (clear_inferiors): Update. + * inferiors.h (for_each_inferior_with_data): Declare. + (clear_inferior_list): Declare. + (one_inferior_p): Declare. + (get_first_inferior): Declare. + * linux-low.c (linux_wait_for_event): Replace accessing list + implemention details with API function. + * server.c (target_running): Ditto. + (accumulate_file_name_length): New function. + (emit_dll_description): New function. + (handle_qxfer_libraries): Replace accessing list implemention + details with API function. + (handle_qxfer_threads_worker): New function. + (handle_qxfer_threads_proper): Replace accessing list implemention + details with API function. + (handle_query): Ditto. + (visit_actioned_threads_callback_ftype): New typedef. + (visit_actioned_threads_data): New struct. + (visit_actioned_threads): Rewrite to be find_inferior callback. + (resume): Call find_inferior. + (handle_status): Replace accessing list implemention + details with API function. + (process_serial_event): Replace accessing list implemention details + with API function. + * target.c (set_desired_inferior): Replace accessing list implemention + details with API function. + * tracepoint.c (same_process_p): New function. + (gdb_agent_about_to_close): Replace accessing list implemention + details with API function. + * win32-low.c (child_delete_thread): Replace accessing list + implemention details with API function. + (match_dll_by_basename): New function. + (dll_is_loaded_by_basename): New function. + (win32_ensure_ntdll_loaded): Replace accessing list implemention + details call to dll_is_loaded_by_basename. + 2014-02-19 Doug Evans * dll.h (struct dll_info): Add comment. diff --git a/gdb/gdbserver/dll.c b/gdb/gdbserver/dll.c index be0e01f3be..52f997c20f 100644 --- a/gdb/gdbserver/dll.c +++ b/gdb/gdbserver/dll.c @@ -110,5 +110,5 @@ void clear_dlls (void) { for_each_inferior (&all_dlls, free_one_dll); - all_dlls.head = all_dlls.tail = NULL; + clear_inferior_list (&all_dlls); } diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h index 4c454a2b7b..0eac5a47d2 100644 --- a/gdb/gdbserver/gdbthread.h +++ b/gdb/gdbserver/gdbthread.h @@ -76,6 +76,8 @@ extern struct inferior_list all_threads; void remove_thread (struct thread_info *thread); void add_thread (ptid_t ptid, void *target_data); +struct thread_info *get_first_thread (void); + struct thread_info *find_thread_ptid (ptid_t ptid); /* Get current thread ID (Linux task ID). */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index e3d28eaeb5..c709b36ba4 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -59,6 +59,24 @@ for_each_inferior (struct inferior_list *list, } } +/* Invoke ACTION for each inferior in LIST, passing DATA to ACTION. */ + +void +for_each_inferior_with_data (struct inferior_list *list, + void (*action) (struct inferior_list_entry *, + void *), + void *data) +{ + struct inferior_list_entry *cur = list->head, *next; + + while (cur != NULL) + { + next = cur->next; + (*action) (cur, data); + cur = next; + } +} + void remove_inferior (struct inferior_list *list, struct inferior_list_entry *entry) @@ -111,20 +129,18 @@ thread_to_gdb_id (struct thread_info *thread) return thread->entry.id; } +/* Wrapper around get_first_inferior to return a struct thread_info *. */ + +struct thread_info * +get_first_thread (void) +{ + return (struct thread_info *) get_first_inferior (&all_threads); +} + struct thread_info * find_thread_ptid (ptid_t ptid) { - struct inferior_list_entry *inf = all_threads.head; - - while (inf != NULL) - { - struct thread_info *thread = get_thread (inf); - if (ptid_equal (thread->entry.id, ptid)) - return thread; - inf = inf->next; - } - - return NULL; + return (struct thread_info *) find_inferior_id (&all_threads, ptid); } ptid_t @@ -153,6 +169,18 @@ remove_thread (struct thread_info *thread) free_one_thread (&thread->entry); } +/* Return a pointer to the first inferior in LIST, or NULL if there isn't one. + This is for cases where the caller needs a thread, but doesn't care + which one. */ + +struct inferior_list_entry * +get_first_inferior (struct inferior_list *list) +{ + if (all_threads.head != NULL) + return all_threads.head; + return NULL; +} + /* Find the first inferior_list_entry E in LIST for which FUNC (E, ARG) returns non-zero. If no entry is found then return NULL. */ @@ -214,14 +242,28 @@ set_inferior_regcache_data (struct thread_info *inferior, void *data) inferior->regcache_data = data; } -#define clear_list(LIST) \ - do { (LIST)->head = (LIST)->tail = NULL; } while (0) +/* Return true if LIST has exactly one entry. */ + +int +one_inferior_p (struct inferior_list *list) +{ + return list->head != NULL && list->head == list->tail; +} + +/* Reset head,tail of LIST, assuming all entries have already been freed. */ + +void +clear_inferior_list (struct inferior_list *list) +{ + list->head = NULL; + list->tail = NULL; +} void clear_inferiors (void) { for_each_inferior (&all_threads, free_one_thread); - clear_list (&all_threads); + clear_inferior_list (&all_threads); clear_dlls (); diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index f02afddb02..8601b7ee4b 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -86,10 +86,21 @@ void add_inferior_to_list (struct inferior_list *list, void for_each_inferior (struct inferior_list *list, void (*action) (struct inferior_list_entry *)); +void for_each_inferior_with_data + (struct inferior_list *list, + void (*action) (struct inferior_list_entry *, void *), + void *data); + +void clear_inferior_list (struct inferior_list *list); + +int one_inferior_p (struct inferior_list *list); + extern struct thread_info *current_inferior; void remove_inferior (struct inferior_list *list, struct inferior_list_entry *entry); +struct inferior_list_entry *get_first_inferior (struct inferior_list *list); + struct process_info *add_process (int pid, int attached); void remove_process (struct process_info *process); struct process_info *find_process_pid (int pid); diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 011ee58da3..2a8302285f 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -1872,7 +1872,7 @@ linux_wait_for_event (ptid_t ptid, int *wstat, int options) if (!non_stop) { - current_inferior = (struct thread_info *) all_threads.head; + current_inferior = get_first_thread (); if (debug_threads) debug_printf ("Current inferior is now %ld\n", lwpid_of (get_thread_lwp (current_inferior))); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 94a72f7599..115aca4d8f 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -192,7 +192,7 @@ struct notif_server notif_stop = static int target_running (void) { - return all_threads.head != NULL; + return get_first_thread () != NULL; } static int @@ -1136,6 +1136,48 @@ handle_qxfer_features (const char *annex, return len; } +/* Worker routine for handle_qxfer_libraries. + Add to the length pointed to by ARG a conservative estimate of the + length needed to transmit the file name of INF. */ + +static void +accumulate_file_name_length (struct inferior_list_entry *inf, void *arg) +{ + struct dll_info *dll = (struct dll_info *) inf; + unsigned int *total_len = arg; + + /* Over-estimate the necessary memory. Assume that every character + in the library name must be escaped. */ + *total_len += 128 + 6 * strlen (dll->name); +} + +/* Worker routine for handle_qxfer_libraries. + Emit the XML to describe the library in INF. */ + +static void +emit_dll_description (struct inferior_list_entry *inf, void *arg) +{ + struct dll_info *dll = (struct dll_info *) inf; + char **p_ptr = arg; + char *p = *p_ptr; + char *name; + + strcpy (p, " name); + strcpy (p, name); + free (name); + p = p + strlen (p); + strcpy (p, "\">base_addr); + p = p + strlen (p); + strcpy (p, "\"/>\n"); + p = p + strlen (p); + + *p_ptr = p; +} + /* Handle qXfer:libraries:read. */ static int @@ -1145,7 +1187,6 @@ handle_qxfer_libraries (const char *annex, { unsigned int total_len; char *document, *p; - struct inferior_list_entry *dll_ptr; if (writebuf != NULL) return -2; @@ -1153,11 +1194,9 @@ handle_qxfer_libraries (const char *annex, if (annex[0] != '\0' || !target_running ()) return -1; - /* Over-estimate the necessary memory. Assume that every character - in the library name must be escaped. */ total_len = 64; - for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) - total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name); + for_each_inferior_with_data (&all_dlls, accumulate_file_name_length, + &total_len); document = malloc (total_len); if (document == NULL) @@ -1166,24 +1205,7 @@ handle_qxfer_libraries (const char *annex, strcpy (document, "\n"); p = document + strlen (document); - for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) - { - struct dll_info *dll = (struct dll_info *) dll_ptr; - char *name; - - strcpy (p, " name); - strcpy (p, name); - free (name); - p = p + strlen (p); - strcpy (p, "\">base_addr); - p = p + strlen (p); - strcpy (p, "\"/>\n"); - p = p + strlen (p); - } + for_each_inferior_with_data (&all_dlls, emit_dll_description, &p); strcpy (p, "\n"); @@ -1285,36 +1307,43 @@ handle_qxfer_statictrace (const char *annex, return nbytes; } +/* Helper for handle_qxfer_threads_proper. + Emit the XML to describe the thread of INF. */ + +static void +handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg) +{ + struct thread_info *thread = (struct thread_info *) inf; + struct buffer *buffer = arg; + ptid_t ptid = thread_to_gdb_id (thread); + char ptid_s[100]; + int core = target_core_of_thread (ptid); + char core_s[21]; + + write_ptid (ptid_s, ptid); + + if (core != -1) + { + sprintf (core_s, "%d", core); + buffer_xml_printf (buffer, "\n", + ptid_s, core_s); + } + else + { + buffer_xml_printf (buffer, "\n", + ptid_s); + } +} + /* Helper for handle_qxfer_threads. */ static void handle_qxfer_threads_proper (struct buffer *buffer) { - struct inferior_list_entry *thread; - buffer_grow_str (buffer, "\n"); - for (thread = all_threads.head; thread; thread = thread->next) - { - ptid_t ptid = thread_to_gdb_id ((struct thread_info *)thread); - char ptid_s[100]; - int core = target_core_of_thread (ptid); - char core_s[21]; - - write_ptid (ptid_s, ptid); - - if (core != -1) - { - sprintf (core_s, "%d", core); - buffer_xml_printf (buffer, "\n", - ptid_s, core_s); - } - else - { - buffer_xml_printf (buffer, "\n", - ptid_s); - } - } + for_each_inferior_with_data (&all_threads, handle_qxfer_threads_worker, + buffer); buffer_grow_str0 (buffer, "\n"); } @@ -1702,7 +1731,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) gdb_id = general_thread; else { - thread_ptr = all_threads.head; + thread_ptr = get_first_inferior (&all_threads); gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); } @@ -1743,7 +1772,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) ptid_t gdb_id; require_running (own_buf); - thread_ptr = all_threads.head; + thread_ptr = get_first_inferior (&all_threads); *own_buf++ = 'm'; gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); @@ -2121,37 +2150,47 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) static void gdb_wants_all_threads_stopped (void); static void resume (struct thread_resume *actions, size_t n); +/* The callback that is passed to visit_actioned_threads. */ +typedef int (visit_actioned_threads_callback_ftype) + (const struct thread_resume *, struct thread_info *); + +/* Struct to pass data to visit_actioned_threads. */ + +struct visit_actioned_threads_data +{ + const struct thread_resume *actions; + size_t num_actions; + visit_actioned_threads_callback_ftype *callback; +}; + /* Call CALLBACK for any thread to which ACTIONS applies to. Returns true if CALLBACK returns true. Returns false if no matching thread - is found or CALLBACK results false. */ + is found or CALLBACK results false. + Note: This function is itself a callback for find_inferior. */ static int -visit_actioned_threads (const struct thread_resume *actions, - size_t num_actions, - int (*callback) (const struct thread_resume *, - struct thread_info *)) +visit_actioned_threads (struct inferior_list_entry *entry, void *datap) { - struct inferior_list_entry *entry; + struct visit_actioned_threads_data *data = datap; + const struct thread_resume *actions = data->actions; + size_t num_actions = data->num_actions; + visit_actioned_threads_callback_ftype *callback = data->callback; + size_t i; - for (entry = all_threads.head; entry != NULL; entry = entry->next) + for (i = 0; i < num_actions; i++) { - size_t i; + const struct thread_resume *action = &actions[i]; - for (i = 0; i < num_actions; i++) + if (ptid_equal (action->thread, minus_one_ptid) + || ptid_equal (action->thread, entry->id) + || ((ptid_get_pid (action->thread) + == ptid_get_pid (entry->id)) + && ptid_get_lwp (action->thread) == -1)) { - const struct thread_resume *action = &actions[i]; + struct thread_info *thread = (struct thread_info *) entry; - if (ptid_equal (action->thread, minus_one_ptid) - || ptid_equal (action->thread, entry->id) - || ((ptid_get_pid (action->thread) - == ptid_get_pid (entry->id)) - && ptid_get_lwp (action->thread) == -1)) - { - struct thread_info *thread = (struct thread_info *) entry; - - if ((*callback) (action, thread)) - return 1; - } + if ((*callback) (action, thread)) + return 1; } } @@ -2309,7 +2348,12 @@ resume (struct thread_resume *actions, size_t num_actions) one with a pending status to report. If so, skip actually resuming/stopping and report the pending event immediately. */ - if (visit_actioned_threads (actions, num_actions, handle_pending_status)) + struct visit_actioned_threads_data data; + + data.actions = actions; + data.num_actions = num_actions; + data.callback = handle_pending_status; + if (find_inferior (&all_threads, visit_actioned_threads, &data) != NULL) return; enable_async_io (); @@ -2782,7 +2826,7 @@ handle_status (char *own_buf) /* If we're still out of luck, simply pick the first thread in the thread list. */ if (thread == NULL) - thread = all_threads.head; + thread = get_first_inferior (&all_threads); if (thread != NULL) { @@ -3541,7 +3585,10 @@ process_serial_event (void) (struct thread_info *) find_inferior_id (&all_threads, general_thread); if (thread == NULL) - thread_id = all_threads.head->id; + { + thread = get_first_thread (); + thread_id = thread->entry.id; + } } general_thread = thread_id; diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index e148f33aeb..dcad5c9467 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -34,7 +34,7 @@ set_desired_inferior (int use_general) found = find_thread_ptid (cont_thread); if (found == NULL) - current_inferior = (struct thread_info *) all_threads.head; + current_inferior = get_first_thread (); else current_inferior = found; } diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 8e294f64c0..7c4b2911b0 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -3943,6 +3943,17 @@ cmd_qtstmat (char *packet) run_inferior_command (packet, strlen (packet) + 1); } +/* Helper for gdb_agent_about_to_close. + Return non-zero if thread ENTRY is in the same process in DATA. */ + +static int +same_process_p (struct inferior_list_entry *entry, void *data) +{ + int *pid = data; + + return ptid_get_pid (entry->id) == *pid; +} + /* Sent the agent a command to close it. */ void @@ -3953,19 +3964,12 @@ gdb_agent_about_to_close (int pid) if (!maybe_write_ipa_not_loaded (buf)) { struct thread_info *save_inferior; - struct inferior_list_entry *inf = all_threads.head; save_inferior = current_inferior; - /* Find a certain thread which belongs to process PID. */ - while (inf != NULL) - { - if (ptid_get_pid (inf->id) == pid) - break; - inf = inf->next; - } - - current_inferior = (struct thread_info *) inf; + /* Find any thread which belongs to process PID. */ + current_inferior = (struct thread_info *) + find_inferior (&all_threads, same_process_p, &pid); strcpy (buf, "close"); diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index f2620a5077..e84306dd27 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -232,7 +232,7 @@ child_delete_thread (DWORD pid, DWORD tid) ptid_t ptid; /* If the last thread is exiting, just return. */ - if (all_threads.head == all_threads.tail) + if (one_inferior_p (&all_threads)) return; ptid = ptid_build (pid, tid, 0); @@ -1142,6 +1142,28 @@ failed: } #ifndef _WIN32_WCE + +/* Helper routine for dll_is_loaded_by_basename. + Return non-zero if the basename in ARG matches the DLL in INF. */ + +static int +match_dll_by_basename (struct inferior_list_entry *inf, void *arg) +{ + struct dll_info *iter = (void *) inf; + const char *basename = arg; + + return strcasecmp (lbasename (iter->name), basename) == 0; +} + +/* Return non-zero if the DLL specified by BASENAME is loaded. */ + +static int +dll_is_loaded_by_basename (const char *basename) +{ + return find_inferior (&all_dlls, match_dll_by_basename, + (void *) basename) != NULL; +} + /* On certain versions of Windows, the information about ntdll.dll is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT, thus preventing us from reporting this DLL as an SO. This has been @@ -1158,20 +1180,14 @@ failed: static void win32_ensure_ntdll_loaded (void) { - struct inferior_list_entry *dll_e; size_t i; HMODULE dh_buf[1]; HMODULE *DllHandle = dh_buf; DWORD cbNeeded; BOOL ok; - for (dll_e = all_dlls.head; dll_e != NULL; dll_e = dll_e->next) - { - struct dll_info *dll = (struct dll_info *) dll_e; - - if (strcasecmp (lbasename (dll->name), "ntdll.dll") == 0) - return; - } + if (dll_is_loaded_by_basename ("ntdll.dll")) + return; if (!load_psapi ()) return;