/* A thread found on the remote target. */
-typedef struct thread_item
+struct thread_item
{
+ explicit thread_item (ptid_t ptid_)
+ : ptid (ptid_)
+ {}
+
+ thread_item (thread_item &&other) = default;
+ thread_item &operator= (thread_item &&other) = default;
+
+ DISABLE_COPY_AND_ASSIGN (thread_item);
+
/* The thread's PTID. */
ptid_t ptid;
- /* The thread's extra info. May be NULL. */
- char *extra;
+ /* The thread's extra info. */
+ std::string extra;
- /* The thread's name. May be NULL. */
- char *name;
+ /* The thread's name. */
+ std::string name;
/* The core the thread was running on. -1 if not known. */
- int core;
+ int core = -1;
/* The thread handle associated with the thread. */
- gdb::byte_vector *thread_handle;
+ gdb::byte_vector thread_handle;
-} 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
struct threads_listing_context
{
- /* The threads found on the remote target. */
- VEC (thread_item_t) *items;
-};
+ /* Return true if this object contains an entry for a thread with ptid
+ PTID. */
-/* Discard the contents of the constructed thread listing context. */
+ bool contains_thread (ptid_t ptid) const
+ {
+ auto match_ptid = [&] (const thread_item &item)
+ {
+ return item.ptid == ptid;
+ };
-static void
-clear_threads_listing_context (void *p)
-{
- struct threads_listing_context *context
- = (struct threads_listing_context *) p;
- int i;
- struct thread_item *item;
+ auto it = std::find_if (this->items.begin (),
+ this->items.end (),
+ match_ptid);
- for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
- {
- xfree (item->extra);
- xfree (item->name);
- delete item->thread_handle;
- }
+ return it != this->items.end ();
+ }
- VEC_free (thread_item_t, context->items);
-}
+ /* Remove the thread with ptid PTID. */
-/* Remove the thread specified as the related_pid field of WS
- from the CONTEXT list. */
+ void remove_thread (ptid_t ptid)
+ {
+ auto match_ptid = [&] (const thread_item &item)
+ {
+ return item.ptid == ptid;
+ };
-static void
-threads_listing_context_remove (struct target_waitstatus *ws,
- struct threads_listing_context *context)
-{
- struct thread_item *item;
- int i;
- ptid_t child_ptid = ws->value.related_pid;
+ auto it = std::remove_if (this->items.begin (),
+ this->items.end (),
+ match_ptid);
- for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
- {
- if (ptid_equal (item->ptid, child_ptid))
- {
- VEC_ordered_remove (thread_item_t, context->items, i);
- break;
- }
- }
-}
+ if (it != this->items.end ())
+ this->items.erase (it);
+ }
+
+ /* The threads found on the remote target. */
+ std::vector<thread_item> items;
+};
static int
remote_newthread_step (threadref *ref, void *data)
{
struct threads_listing_context *context
= (struct threads_listing_context *) data;
- struct thread_item item;
- int pid = ptid_get_pid (inferior_ptid);
-
- item.ptid = ptid_build (pid, threadref_to_int (ref), 0);
- item.core = -1;
- item.name = NULL;
- item.extra = NULL;
- item.thread_handle = nullptr;
+ int pid = inferior_ptid.pid ();
+ int lwp = threadref_to_int (ref);
+ ptid_t ptid (pid, lwp);
- VEC_safe_push (thread_item_t, context->items, &item);
+ context->items.emplace_back (ptid);
return 1; /* continue iterator */
}
{
struct threads_listing_context *data
= (struct threads_listing_context *) user_data;
-
- struct thread_item item;
- char *id;
struct gdb_xml_value *attr;
- id = (char *) xml_find_attribute (attributes, "id")->value;
- item.ptid = read_ptid (id, NULL);
+ char *id = (char *) xml_find_attribute (attributes, "id")->value;
+ ptid_t ptid = read_ptid (id, NULL);
+
+ data->items.emplace_back (ptid);
+ thread_item &item = data->items.back ();
attr = xml_find_attribute (attributes, "core");
if (attr != NULL)
item.core = *(ULONGEST *) attr->value;
- else
- item.core = -1;
attr = xml_find_attribute (attributes, "name");
- item.name = attr != NULL ? xstrdup ((const char *) attr->value) : NULL;
+ if (attr != NULL)
+ item.name = (const char *) attr->value;
attr = xml_find_attribute (attributes, "handle");
if (attr != NULL)
- {
- item.thread_handle = new gdb::byte_vector
- (strlen ((const char *) attr->value) / 2);
- hex2bin ((const char *) attr->value, item.thread_handle->data (),
- item.thread_handle->size ());
- }
- else
- item.thread_handle = nullptr;
-
- item.extra = 0;
-
- VEC_safe_push (thread_item_t, data->items, &item);
+ item.thread_handle = hex2bin ((const char *) attr->value);
}
static void
struct threads_listing_context *data
= (struct threads_listing_context *) user_data;
- if (body_text && *body_text)
- VEC_last (thread_item_t, data->items)->extra = xstrdup (body_text);
+ if (body_text != NULL && *body_text != '\0')
+ data->items.back ().extra = body_text;
}
const struct gdb_xml_attribute thread_attributes[] = {
{
do
{
- struct thread_item item;
-
- item.ptid = read_ptid (bufp, &bufp);
- item.core = -1;
- item.name = NULL;
- item.extra = NULL;
- item.thread_handle = nullptr;
-
- VEC_safe_push (thread_item_t, context->items, &item);
+ ptid_t ptid = read_ptid (bufp, &bufp);
+ context->items.emplace_back (ptid);
}
while (*bufp++ == ','); /* comma-separated list */
putpkt ("qsThreadInfo");
remote_update_thread_list (struct target_ops *ops)
{
struct threads_listing_context context;
- struct cleanup *old_chain;
int got_list = 0;
- 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. */
|| remote_get_threads_with_ql (ops, &context))
{
int i;
- struct thread_item *item;
struct thread_info *tp, *tmp;
got_list = 1;
- if (VEC_empty (thread_item_t, context.items)
+ if (context.items.empty ()
&& remote_thread_always_alive (ops, inferior_ptid))
{
/* Some targets don't really support threads, but still
listing packets, instead of replying "packet not
supported". Exit early so we don't delete the main
thread. */
- do_cleanups (old_chain);
return;
}
target. */
ALL_THREADS_SAFE (tp, tmp)
{
- for (i = 0;
- VEC_iterate (thread_item_t, context.items, i, item);
- ++i)
- {
- if (ptid_equal (item->ptid, tp->ptid))
- break;
- }
-
- if (i == VEC_length (thread_item_t, context.items))
+ if (!context.contains_thread (tp->ptid))
{
/* Not found. */
delete_thread (tp->ptid);
remove_new_fork_children (&context);
/* And now add threads we don't know about yet to our list. */
- for (i = 0;
- VEC_iterate (thread_item_t, context.items, i, item);
- ++i)
+ for (thread_item &item : context.items)
{
- if (!ptid_equal (item->ptid, null_ptid))
+ if (item.ptid != null_ptid)
{
struct private_thread_info *info;
/* In non-stop mode, we assume new found threads are
stopped. */
int executing = target_is_non_stop_p () ? 1 : 0;
- remote_notice_new_inferior (item->ptid, executing);
+ remote_notice_new_inferior (item.ptid, executing);
- info = get_private_info_ptid (item->ptid);
- info->core = item->core;
- info->extra = item->extra;
- item->extra = NULL;
- info->name = item->name;
- item->name = NULL;
- info->thread_handle = item->thread_handle;
- item->thread_handle = nullptr;
+ info = get_private_info_ptid (item.ptid);
+ info->core = item.core;
+ info->extra = xstrdup (item.extra.c_str ());
+ info->name = xstrdup (item.name.c_str ());
+ info->thread_handle
+ = new gdb::byte_vector (std::move (item.thread_handle));
}
}
}
no-op. See remote_thread_alive. */
prune_threads ();
}
-
- do_cleanups (old_chain);
}
/*
if (event->ws.kind == TARGET_WAITKIND_FORKED
|| event->ws.kind == TARGET_WAITKIND_VFORKED
|| event->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
- threads_listing_context_remove (&event->ws, context);
+ context->remove_thread (event->ws.value.related_pid);
return 1;
}
struct target_waitstatus *ws = thread_pending_fork_status (thread);
if (is_pending_fork_parent (ws, pid, thread->ptid))
- {
- threads_listing_context_remove (ws, context);
- }
+ context->remove_thread (ws->value.related_pid);
}
/* Check for any pending fork events (not reported or processed yet)
--- /dev/null
+/* Unit tests for the rsp-low.c file.
+
+ Copyright (C) 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "selftest.h"
+#include "common/rsp-low.h"
+
+namespace selftests {
+namespace rsp_low {
+
+/* Test the variant of hex2bin that returns a byte_vector. */
+
+static void test_hex2bin_byte_vector ()
+{
+ gdb::byte_vector bv;
+
+ /* Test an empty string. */
+ bv = hex2bin ("");
+ SELF_CHECK (bv.size () == 0);
+
+ /* Test a well-formated hex string. */
+ bv = hex2bin ("abcd01");
+ SELF_CHECK (bv.size () == 3);
+ SELF_CHECK (bv[0] == 0xab);
+ SELF_CHECK (bv[1] == 0xcd);
+ SELF_CHECK (bv[2] == 0x01);
+
+ /* Test an odd-length hex string. */
+ bv = hex2bin ("0123c");
+ SELF_CHECK (bv.size () == 2);
+ SELF_CHECK (bv[0] == 0x01);
+ SELF_CHECK (bv[1] == 0x23);
+}
+
+} /* namespace rsp_low */
+} /* namespace selftests */
+
+void
+_initialize_rsp_low_selftests ()
+{
+ selftests::register_test ("hex2bin_byte_vector",
+ selftests::rsp_low::test_hex2bin_byte_vector);
+}