+2014-02-19 Doug Evans <dje@google.com>
+
+ * 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 <dje@google.com>
* dll.h (struct dll_info): Add comment.
clear_dlls (void)
{
for_each_inferior (&all_dlls, free_one_dll);
- all_dlls.head = all_dlls.tail = NULL;
+ clear_inferior_list (&all_dlls);
}
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). */
}
}
+/* 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)
return thread->entry.id;
}
+/* Wrapper around get_first_inferior to return a struct thread_info *. */
+
struct thread_info *
-find_thread_ptid (ptid_t ptid)
+get_first_thread (void)
{
- 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 (struct thread_info *) get_first_inferior (&all_threads);
+}
- return NULL;
+struct thread_info *
+find_thread_ptid (ptid_t ptid)
+{
+ return (struct thread_info *) find_inferior_id (&all_threads, ptid);
}
ptid_t
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. */
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 ();
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);
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)));
static int
target_running (void)
{
- return all_threads.head != NULL;
+ return get_first_thread () != NULL;
}
static int
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, " <library name=\"");
+ p = p + strlen (p);
+ name = xml_escape_text (dll->name);
+ strcpy (p, name);
+ free (name);
+ p = p + strlen (p);
+ strcpy (p, "\"><segment address=\"");
+ p = p + strlen (p);
+ sprintf (p, "0x%lx", (long) dll->base_addr);
+ p = p + strlen (p);
+ strcpy (p, "\"/></library>\n");
+ p = p + strlen (p);
+
+ *p_ptr = p;
+}
+
/* Handle qXfer:libraries:read. */
static int
{
unsigned int total_len;
char *document, *p;
- struct inferior_list_entry *dll_ptr;
if (writebuf != NULL)
return -2;
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)
strcpy (document, "<library-list>\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, " <library name=\"");
- p = p + strlen (p);
- name = xml_escape_text (dll->name);
- strcpy (p, name);
- free (name);
- p = p + strlen (p);
- strcpy (p, "\"><segment address=\"");
- p = p + strlen (p);
- sprintf (p, "0x%lx", (long) dll->base_addr);
- p = p + strlen (p);
- strcpy (p, "\"/></library>\n");
- p = p + strlen (p);
- }
+ for_each_inferior_with_data (&all_dlls, emit_dll_description, &p);
strcpy (p, "</library-list>\n");
return nbytes;
}
-/* Helper for handle_qxfer_threads. */
+/* Helper for handle_qxfer_threads_proper.
+ Emit the XML to describe the thread of INF. */
static void
-handle_qxfer_threads_proper (struct buffer *buffer)
+handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
{
- struct inferior_list_entry *thread;
+ 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];
- buffer_grow_str (buffer, "<threads>\n");
+ write_ptid (ptid_s, ptid);
- for (thread = all_threads.head; thread; thread = thread->next)
+ if (core != -1)
{
- 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];
+ sprintf (core_s, "%d", core);
+ buffer_xml_printf (buffer, "<thread id=\"%s\" core=\"%s\"/>\n",
+ ptid_s, core_s);
+ }
+ else
+ {
+ buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
+ ptid_s);
+ }
+}
- write_ptid (ptid_s, ptid);
+/* Helper for handle_qxfer_threads. */
- if (core != -1)
- {
- sprintf (core_s, "%d", core);
- buffer_xml_printf (buffer, "<thread id=\"%s\" core=\"%s\"/>\n",
- ptid_s, core_s);
- }
- else
- {
- buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
- ptid_s);
- }
- }
+static void
+handle_qxfer_threads_proper (struct buffer *buffer)
+{
+ buffer_grow_str (buffer, "<threads>\n");
+
+ for_each_inferior_with_data (&all_threads, handle_qxfer_threads_worker,
+ buffer);
buffer_grow_str0 (buffer, "</threads>\n");
}
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);
}
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);
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];
-
- 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;
+ struct thread_info *thread = (struct thread_info *) entry;
- if ((*callback) (action, thread))
- return 1;
- }
+ if ((*callback) (action, thread))
+ return 1;
}
}
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 ();
/* 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)
{
(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;
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;
}
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
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");
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);
}
#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
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;