static ptid_t remote_current_thread (ptid_t oldptid);
-static void remote_find_new_threads (void);
-
static int putpkt_binary (const char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
return resultcount;
}
+/* Fetch the next batch of threads from the remote. Returns -1 if the
+ qL packet is not supported, 0 on error and 1 on success. */
+
static int
remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
int *done, int *result_count, threadref *threadlist)
pack_threadlist_request (rs->buf, startflag, result_limit, nextthread);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
-
if (*rs->buf == '\0')
- return 0;
- else
- *result_count =
- parse_threadlist_response (rs->buf + 2, result_limit,
- &rs->echo_nextthread, threadlist, done);
+ {
+ /* Packet not supported. */
+ return -1;
+ }
+
+ *result_count =
+ parse_threadlist_response (rs->buf + 2, result_limit,
+ &rs->echo_nextthread, threadlist, done);
if (!threadmatch (&rs->echo_nextthread, nextthread))
{
return result;
}
-/* This is the interface between remote and threads, remotes upper
- interface. */
-
-/* remote_find_new_threads retrieves the thread list and for each
- thread in the list, looks up the thread in GDB's internal list,
- adding the thread if it does not already exist. This involves
- getting partial thread lists from the remote target so, polling the
- quit_flag is required. */
-
+/* Fetch the list of remote threads, with the qL packet, and call
+ STEPFUNCTION for each thread found. Stops iterating and returns 1
+ if STEPFUNCTION returns true. Stops iterating and returns 0 if the
+ STEPFUNCTION returns false. If the packet is not supported,
+ returns -1. */
static int
remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
warning (_("Remote fetch threadlist -infinite loop-."));
break;
}
- if (!remote_get_threadlist (startflag, &rs->nextthread,
- MAXTHREADLISTRESULTS,
- &done, &result_count, rs->resultthreadlist))
- {
- result = 0;
- break;
- }
+ result = remote_get_threadlist (startflag, &rs->nextthread,
+ MAXTHREADLISTRESULTS,
+ &done, &result_count,
+ rs->resultthreadlist);
+ if (result <= 0)
+ break;
/* Clear for later iterations. */
startflag = 0;
/* Setup to resume next batch of thread references, set nextthread. */
&rs->resultthreadlist[result_count - 1]);
i = 0;
while (result_count--)
- if (!(result = (*stepfunction) (&rs->resultthreadlist[i++], context)))
- break;
+ {
+ if (!(*stepfunction) (&rs->resultthreadlist[i++], context))
+ {
+ result = 0;
+ break;
+ }
+ }
}
return result;
}
+/* A thread found on the remote target. */
+
+typedef struct thread_item
+{
+ /* The thread's PTID. */
+ ptid_t ptid;
+
+ /* The thread's extra info. May be NULL. */
+ char *extra;
+
+ /* The core the thread was running on. -1 if not known. */
+ int core;
+} thread_item_t;
+DEF_VEC_O(thread_item_t);
+
+/* Context passed around to the various methods listing remote
+ threads. As new threads are found, they're added to the ITEMS
+ vector. */
+
+struct threads_listing_context
+{
+ /* The threads found on the remote target. */
+ VEC (thread_item_t) *items;
+};
+
static int
-remote_newthread_step (threadref *ref, void *context)
+remote_newthread_step (threadref *ref, void *data)
{
+ struct threads_listing_context *context = data;
+ struct thread_item item;
int pid = ptid_get_pid (inferior_ptid);
- ptid_t ptid = ptid_build (pid, threadref_to_int (ref), 0);
- if (!in_thread_list (ptid))
- add_thread (ptid);
+ item.ptid = ptid_build (pid, threadref_to_int (ref), 0);
+ item.core = -1;
+ item.extra = NULL;
+
+ VEC_safe_push (thread_item_t, context->items, &item);
+
return 1; /* continue iterator */
}
return oldpid;
}
-/* Find new threads for info threads command.
- * Original version, using John Metzler's thread protocol.
- */
+/* List remote threads using the deprecated qL packet. */
-static void
-remote_find_new_threads (void)
+static int
+remote_get_threads_with_ql (struct target_ops *ops,
+ struct threads_listing_context *context)
{
- remote_threadlist_iterator (remote_newthread_step, 0,
- CRAZY_MAX_THREADS);
+ if (remote_threadlist_iterator (remote_newthread_step, context,
+ CRAZY_MAX_THREADS) >= 0)
+ return 1;
+
+ return 0;
}
#if defined(HAVE_LIBEXPAT)
-typedef struct thread_item
-{
- ptid_t ptid;
- char *extra;
- int core;
-} thread_item_t;
-DEF_VEC_O(thread_item_t);
-
-struct threads_parsing_context
-{
- VEC (thread_item_t) *items;
-};
-
static void
start_thread (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- struct threads_parsing_context *data = user_data;
+ struct threads_listing_context *data = user_data;
struct thread_item item;
char *id;
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
- struct threads_parsing_context *data = user_data;
+ struct threads_listing_context *data = user_data;
if (body_text && *body_text)
VEC_last (thread_item_t, data->items)->extra = xstrdup (body_text);
/* Discard the contents of the constructed thread info context. */
static void
-clear_threads_parsing_context (void *p)
+clear_threads_listing_context (void *p)
{
- struct threads_parsing_context *context = p;
+ struct threads_listing_context *context = p;
int i;
struct thread_item *item;
#endif
-/*
- * Find all threads for info threads command.
- * Uses new thread protocol contributed by Cisco.
- * Falls back and attempts to use the older method (above)
- * if the target doesn't respond to the new method.
- */
+/* List remote threads using qXfer:threads:read. */
-static void
-remote_threads_info (struct target_ops *ops)
+static int
+remote_get_threads_with_qxfer (struct target_ops *ops,
+ struct threads_listing_context *context)
{
- struct remote_state *rs = get_remote_state ();
- char *bufp;
- ptid_t new_thread;
-
- if (rs->remote_desc == 0) /* paranoia */
- error (_("Command can only be used when connected to the remote target."));
-
#if defined(HAVE_LIBEXPAT)
if (packet_support (PACKET_qXfer_threads) == PACKET_ENABLE)
{
- char *xml = target_read_stralloc (¤t_target,
- TARGET_OBJECT_THREADS, NULL);
-
+ char *xml = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
struct cleanup *back_to = make_cleanup (xfree, xml);
- if (xml && *xml)
+ if (xml != NULL && *xml != '\0')
{
- struct threads_parsing_context context;
-
- context.items = NULL;
- make_cleanup (clear_threads_parsing_context, &context);
-
- if (gdb_xml_parse_quick (_("threads"), "threads.dtd",
- threads_elements, xml, &context) == 0)
- {
- int i;
- struct thread_item *item;
-
- for (i = 0;
- VEC_iterate (thread_item_t, context.items, i, item);
- ++i)
- {
- if (!ptid_equal (item->ptid, null_ptid))
- {
- struct private_thread_info *info;
- /* In non-stop mode, we assume new found threads
- are running until proven otherwise with a
- stop reply. In all-stop, we can only get
- here if all threads are stopped. */
- int running = non_stop ? 1 : 0;
-
- remote_notice_new_inferior (item->ptid, running);
-
- info = demand_private_info (item->ptid);
- info->core = item->core;
- info->extra = item->extra;
- item->extra = NULL;
- }
- }
- }
+ gdb_xml_parse_quick (_("threads"), "threads.dtd",
+ threads_elements, xml, context);
}
do_cleanups (back_to);
- return;
+ return 1;
}
#endif
+ return 0;
+}
+
+/* List remote threads using qfThreadInfo/qsThreadInfo. */
+
+static int
+remote_get_threads_with_qthreadinfo (struct target_ops *ops,
+ struct threads_listing_context *context)
+{
+ struct remote_state *rs = get_remote_state ();
+
if (rs->use_threadinfo_query)
{
+ char *bufp;
+
putpkt ("qfThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
bufp = rs->buf;
if (bufp[0] != '\0') /* q packet recognized */
{
- struct cleanup *old_chain;
- char *saved_reply;
-
- /* remote_notice_new_inferior (in the loop below) may make
- new RSP calls, which clobber rs->buf. Work with a
- copy. */
- bufp = saved_reply = xstrdup (rs->buf);
- old_chain = make_cleanup (free_current_contents, &saved_reply);
-
while (*bufp++ == 'm') /* reply contains one or more TID */
{
do
{
- new_thread = read_ptid (bufp, &bufp);
- if (!ptid_equal (new_thread, null_ptid))
- {
- /* In non-stop mode, we assume new found threads
- are running until proven otherwise with a
- stop reply. In all-stop, we can only get
- here if all threads are stopped. */
- int running = non_stop ? 1 : 0;
+ struct thread_item item;
- remote_notice_new_inferior (new_thread, running);
- }
+ item.ptid = read_ptid (bufp, &bufp);
+ item.core = -1;
+ item.extra = NULL;
+
+ VEC_safe_push (thread_item_t, context->items, &item);
}
while (*bufp++ == ','); /* comma-separated list */
- free_current_contents (&saved_reply);
putpkt ("qsThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
- bufp = saved_reply = xstrdup (rs->buf);
+ bufp = rs->buf;
}
- do_cleanups (old_chain);
- return; /* done */
+ return 1;
+ }
+ else
+ {
+ /* Packet not recognized. */
+ rs->use_threadinfo_query = 0;
}
}
- /* Only qfThreadInfo is supported in non-stop mode. */
- if (non_stop)
- return;
+ return 0;
+}
+
+/* Implement the to_find_new_threads function for the remote
+ targets. */
+
+static void
+remote_threads_info (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct threads_listing_context context;
+ struct cleanup *old_chain;
+
+ context.items = NULL;
+ old_chain = make_cleanup (clear_threads_listing_context, &context);
+
+ /* We have a few different mechanisms to fetch the thread list. Try
+ them all, starting with the most preferred one first, falling
+ back to older methods. */
+ if (remote_get_threads_with_qxfer (ops, &context)
+ || remote_get_threads_with_qthreadinfo (ops, &context)
+ || remote_get_threads_with_ql (ops, &context))
+ {
+ int i;
+ struct thread_item *item;
- /* Else fall back to old method based on jmetzler protocol. */
- rs->use_threadinfo_query = 0;
- remote_find_new_threads ();
- return;
+ /* Add threads we don't know about yet to our list. */
+ for (i = 0;
+ VEC_iterate (thread_item_t, context.items, i, item);
+ ++i)
+ {
+ if (!ptid_equal (item->ptid, null_ptid))
+ {
+ struct private_thread_info *info;
+ /* In non-stop mode, we assume new found threads are
+ running until proven otherwise with a stop reply. In
+ all-stop, we can only get here if all threads are
+ stopped. */
+ int running = non_stop ? 1 : 0;
+
+ remote_notice_new_inferior (item->ptid, running);
+
+ info = demand_private_info (item->ptid);
+ info->core = item->core;
+ info->extra = item->extra;
+ item->extra = NULL;
+ }
+ }
+ }
+
+ do_cleanups (old_chain);
}
/*