Replace code accessing list implementation details with API calls.

* 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.
This commit is contained in:
Doug Evans
2014-02-19 15:28:50 -08:00
parent b5ad007edc
commit 649ebbcaef
10 changed files with 279 additions and 109 deletions

View File

@ -1,3 +1,51 @@
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> 2014-02-19 Doug Evans <dje@google.com>
* dll.h (struct dll_info): Add comment. * dll.h (struct dll_info): Add comment.

View File

@ -110,5 +110,5 @@ void
clear_dlls (void) clear_dlls (void)
{ {
for_each_inferior (&all_dlls, free_one_dll); for_each_inferior (&all_dlls, free_one_dll);
all_dlls.head = all_dlls.tail = NULL; clear_inferior_list (&all_dlls);
} }

View File

@ -76,6 +76,8 @@ extern struct inferior_list all_threads;
void remove_thread (struct thread_info *thread); void remove_thread (struct thread_info *thread);
void add_thread (ptid_t ptid, void *target_data); 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); struct thread_info *find_thread_ptid (ptid_t ptid);
/* Get current thread ID (Linux task ID). */ /* Get current thread ID (Linux task ID). */

View File

@ -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 void
remove_inferior (struct inferior_list *list, remove_inferior (struct inferior_list *list,
struct inferior_list_entry *entry) struct inferior_list_entry *entry)
@ -111,20 +129,18 @@ thread_to_gdb_id (struct thread_info *thread)
return thread->entry.id; 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 * struct thread_info *
find_thread_ptid (ptid_t ptid) find_thread_ptid (ptid_t ptid)
{ {
struct inferior_list_entry *inf = all_threads.head; return (struct thread_info *) find_inferior_id (&all_threads, ptid);
while (inf != NULL)
{
struct thread_info *thread = get_thread (inf);
if (ptid_equal (thread->entry.id, ptid))
return thread;
inf = inf->next;
}
return NULL;
} }
ptid_t ptid_t
@ -153,6 +169,18 @@ remove_thread (struct thread_info *thread)
free_one_thread (&thread->entry); 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) /* 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. */ 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; inferior->regcache_data = data;
} }
#define clear_list(LIST) \ /* Return true if LIST has exactly one entry. */
do { (LIST)->head = (LIST)->tail = NULL; } while (0)
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 void
clear_inferiors (void) clear_inferiors (void)
{ {
for_each_inferior (&all_threads, free_one_thread); for_each_inferior (&all_threads, free_one_thread);
clear_list (&all_threads); clear_inferior_list (&all_threads);
clear_dlls (); clear_dlls ();

View File

@ -86,10 +86,21 @@ void add_inferior_to_list (struct inferior_list *list,
void for_each_inferior (struct inferior_list *list, void for_each_inferior (struct inferior_list *list,
void (*action) (struct inferior_list_entry *)); 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; extern struct thread_info *current_inferior;
void remove_inferior (struct inferior_list *list, void remove_inferior (struct inferior_list *list,
struct inferior_list_entry *entry); 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); struct process_info *add_process (int pid, int attached);
void remove_process (struct process_info *process); void remove_process (struct process_info *process);
struct process_info *find_process_pid (int pid); struct process_info *find_process_pid (int pid);

View File

@ -1872,7 +1872,7 @@ linux_wait_for_event (ptid_t ptid, int *wstat, int options)
if (!non_stop) if (!non_stop)
{ {
current_inferior = (struct thread_info *) all_threads.head; current_inferior = get_first_thread ();
if (debug_threads) if (debug_threads)
debug_printf ("Current inferior is now %ld\n", debug_printf ("Current inferior is now %ld\n",
lwpid_of (get_thread_lwp (current_inferior))); lwpid_of (get_thread_lwp (current_inferior)));

View File

@ -192,7 +192,7 @@ struct notif_server notif_stop =
static int static int
target_running (void) target_running (void)
{ {
return all_threads.head != NULL; return get_first_thread () != NULL;
} }
static int static int
@ -1136,6 +1136,48 @@ handle_qxfer_features (const char *annex,
return len; 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. */ /* Handle qXfer:libraries:read. */
static int static int
@ -1145,7 +1187,6 @@ handle_qxfer_libraries (const char *annex,
{ {
unsigned int total_len; unsigned int total_len;
char *document, *p; char *document, *p;
struct inferior_list_entry *dll_ptr;
if (writebuf != NULL) if (writebuf != NULL)
return -2; return -2;
@ -1153,11 +1194,9 @@ handle_qxfer_libraries (const char *annex,
if (annex[0] != '\0' || !target_running ()) if (annex[0] != '\0' || !target_running ())
return -1; return -1;
/* Over-estimate the necessary memory. Assume that every character
in the library name must be escaped. */
total_len = 64; total_len = 64;
for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) for_each_inferior_with_data (&all_dlls, accumulate_file_name_length,
total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name); &total_len);
document = malloc (total_len); document = malloc (total_len);
if (document == NULL) if (document == NULL)
@ -1166,24 +1205,7 @@ handle_qxfer_libraries (const char *annex,
strcpy (document, "<library-list>\n"); strcpy (document, "<library-list>\n");
p = document + strlen (document); p = document + strlen (document);
for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next) for_each_inferior_with_data (&all_dlls, emit_dll_description, &p);
{
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);
}
strcpy (p, "</library-list>\n"); strcpy (p, "</library-list>\n");
@ -1285,36 +1307,43 @@ handle_qxfer_statictrace (const char *annex,
return nbytes; 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, "<thread id=\"%s\" core=\"%s\"/>\n",
ptid_s, core_s);
}
else
{
buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
ptid_s);
}
}
/* Helper for handle_qxfer_threads. */ /* Helper for handle_qxfer_threads. */
static void static void
handle_qxfer_threads_proper (struct buffer *buffer) handle_qxfer_threads_proper (struct buffer *buffer)
{ {
struct inferior_list_entry *thread;
buffer_grow_str (buffer, "<threads>\n"); buffer_grow_str (buffer, "<threads>\n");
for (thread = all_threads.head; thread; thread = thread->next) for_each_inferior_with_data (&all_threads, handle_qxfer_threads_worker,
{ buffer);
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, "<thread id=\"%s\" core=\"%s\"/>\n",
ptid_s, core_s);
}
else
{
buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
ptid_s);
}
}
buffer_grow_str0 (buffer, "</threads>\n"); buffer_grow_str0 (buffer, "</threads>\n");
} }
@ -1702,7 +1731,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
gdb_id = general_thread; gdb_id = general_thread;
else else
{ {
thread_ptr = all_threads.head; thread_ptr = get_first_inferior (&all_threads);
gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); 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; ptid_t gdb_id;
require_running (own_buf); require_running (own_buf);
thread_ptr = all_threads.head; thread_ptr = get_first_inferior (&all_threads);
*own_buf++ = 'm'; *own_buf++ = 'm';
gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr); 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 gdb_wants_all_threads_stopped (void);
static void resume (struct thread_resume *actions, size_t n); 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 /* Call CALLBACK for any thread to which ACTIONS applies to. Returns
true if CALLBACK returns true. Returns false if no matching thread 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 static int
visit_actioned_threads (const struct thread_resume *actions, visit_actioned_threads (struct inferior_list_entry *entry, void *datap)
size_t num_actions,
int (*callback) (const struct thread_resume *,
struct thread_info *))
{ {
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) if ((*callback) (action, thread))
|| ptid_equal (action->thread, entry->id) return 1;
|| ((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;
}
} }
} }
@ -2309,7 +2348,12 @@ resume (struct thread_resume *actions, size_t num_actions)
one with a pending status to report. If so, skip actually one with a pending status to report. If so, skip actually
resuming/stopping and report the pending event resuming/stopping and report the pending event
immediately. */ 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; return;
enable_async_io (); 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 /* If we're still out of luck, simply pick the first thread in
the thread list. */ the thread list. */
if (thread == NULL) if (thread == NULL)
thread = all_threads.head; thread = get_first_inferior (&all_threads);
if (thread != NULL) if (thread != NULL)
{ {
@ -3541,7 +3585,10 @@ process_serial_event (void)
(struct thread_info *) find_inferior_id (&all_threads, (struct thread_info *) find_inferior_id (&all_threads,
general_thread); general_thread);
if (thread == NULL) if (thread == NULL)
thread_id = all_threads.head->id; {
thread = get_first_thread ();
thread_id = thread->entry.id;
}
} }
general_thread = thread_id; general_thread = thread_id;

View File

@ -34,7 +34,7 @@ set_desired_inferior (int use_general)
found = find_thread_ptid (cont_thread); found = find_thread_ptid (cont_thread);
if (found == NULL) if (found == NULL)
current_inferior = (struct thread_info *) all_threads.head; current_inferior = get_first_thread ();
else else
current_inferior = found; current_inferior = found;
} }

View File

@ -3943,6 +3943,17 @@ cmd_qtstmat (char *packet)
run_inferior_command (packet, strlen (packet) + 1); 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. */ /* Sent the agent a command to close it. */
void void
@ -3953,19 +3964,12 @@ gdb_agent_about_to_close (int pid)
if (!maybe_write_ipa_not_loaded (buf)) if (!maybe_write_ipa_not_loaded (buf))
{ {
struct thread_info *save_inferior; struct thread_info *save_inferior;
struct inferior_list_entry *inf = all_threads.head;
save_inferior = current_inferior; save_inferior = current_inferior;
/* Find a certain thread which belongs to process PID. */ /* Find any thread which belongs to process PID. */
while (inf != NULL) current_inferior = (struct thread_info *)
{ find_inferior (&all_threads, same_process_p, &pid);
if (ptid_get_pid (inf->id) == pid)
break;
inf = inf->next;
}
current_inferior = (struct thread_info *) inf;
strcpy (buf, "close"); strcpy (buf, "close");

View File

@ -232,7 +232,7 @@ child_delete_thread (DWORD pid, DWORD tid)
ptid_t ptid; ptid_t ptid;
/* If the last thread is exiting, just return. */ /* If the last thread is exiting, just return. */
if (all_threads.head == all_threads.tail) if (one_inferior_p (&all_threads))
return; return;
ptid = ptid_build (pid, tid, 0); ptid = ptid_build (pid, tid, 0);
@ -1142,6 +1142,28 @@ failed:
} }
#ifndef _WIN32_WCE #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 /* On certain versions of Windows, the information about ntdll.dll
is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT, 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 thus preventing us from reporting this DLL as an SO. This has been
@ -1158,20 +1180,14 @@ failed:
static void static void
win32_ensure_ntdll_loaded (void) win32_ensure_ntdll_loaded (void)
{ {
struct inferior_list_entry *dll_e;
size_t i; size_t i;
HMODULE dh_buf[1]; HMODULE dh_buf[1];
HMODULE *DllHandle = dh_buf; HMODULE *DllHandle = dh_buf;
DWORD cbNeeded; DWORD cbNeeded;
BOOL ok; BOOL ok;
for (dll_e = all_dlls.head; dll_e != NULL; dll_e = dll_e->next) if (dll_is_loaded_by_basename ("ntdll.dll"))
{ return;
struct dll_info *dll = (struct dll_info *) dll_e;
if (strcasecmp (lbasename (dll->name), "ntdll.dll") == 0)
return;
}
if (!load_psapi ()) if (!load_psapi ())
return; return;