mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-23 03:29:47 +08:00
Implement core awareness.
* bcache.c (compare_ints): Remove (print_percentage): Use compare_positive_ints. * defs.h (compare_positive_ints): Declare. * linux-nat.h (struct lin_lwp): New field core. (linux_nat_core_of_thread_1): Declare. * linux-nat.c (add_lwp): Init the 'core' field. (linux_nat_wait_1): Record the core. (linux_nat_core_of_thread_1, linux_nat_core_of_thread): New. (linux_nat_add_target): Register the above. * linux-thread-db.c (update_thread_core): New. (thread_db_find_new_threads): Update core information for every thread. * remote.c (struct private_thread_info): New. (free_private_thread_info, demand_private_info): New. (PACKET_qXfer_threads, use_osdata_threads): New. (struct thread_item, threads_parsing_context (start_thread, end_thread, thread_attributes) (thread_children, threads_children, threads_elements): New. (remote_threads_info): Try qXfer:threads before anything else. (remote_protocol_packets): Register qXfer:threads. (remote_open_1): Init use_osdata_threads. (struct stop_reply): New field 'core'. (remote_parse_stop_reply): Parse core number. (process_stop_reply): Record core number. (remote_xfer_partial): Handle qXfer:threads. (remote_core_of_thread): New. (init_remote_ops): Register remote_core_of_thread. (_initialize_remote): Register qXfer:read. * target.c (target_core_of_thread): New * target.h (enum target_object): New value TARGET_OBJECT_THREADS. (struct target_ops): New field to_core_of_threads. (target_core_of_thread): Declare. * gdbthread.h (struct thread_info): New field private_dtor. * thread.c (print_thread_info): Report the core. * ui-out.c (MAX_UI_OUT_LEVELS): Increase. * utils.c (compare_positive_ints): New. * features/threads.dtd: New. * mi/mi-interp.c (mi_on_normal_stop): Report the core. * mi/mi-main.c (struct collect_cores_data, collect_cores) (do_nothing, free_vector_of_osdata_items) (splay_tree_int_comparator, free_splay_tree): New. (print_one_inferior_data): Implemented printing of selected inferiors. Collect and print cores. (output_cores): New. (mi_cmd_list_thread_groups): Support --recurse. Permit specifying thread groups together with --available.
This commit is contained in:
218
gdb/remote.c
218
gdb/remote.c
@ -60,6 +60,7 @@
|
||||
#include "remote-fileio.h"
|
||||
#include "gdb/fileio.h"
|
||||
#include "gdb_stat.h"
|
||||
#include "xml-support.h"
|
||||
|
||||
#include "memory-map.h"
|
||||
|
||||
@ -324,6 +325,20 @@ struct remote_state
|
||||
int ctrlc_pending_p;
|
||||
};
|
||||
|
||||
/* Private data that we'll store in (struct thread_info)->private. */
|
||||
struct private_thread_info
|
||||
{
|
||||
char *extra;
|
||||
int core;
|
||||
};
|
||||
|
||||
static void
|
||||
free_private_thread_info (struct private_thread_info *info)
|
||||
{
|
||||
xfree (info->extra);
|
||||
xfree (info);
|
||||
}
|
||||
|
||||
/* Returns true if the multi-process extensions are in effect. */
|
||||
static int
|
||||
remote_multi_process_p (struct remote_state *rs)
|
||||
@ -1121,6 +1136,7 @@ enum {
|
||||
PACKET_qXfer_spu_read,
|
||||
PACKET_qXfer_spu_write,
|
||||
PACKET_qXfer_osdata,
|
||||
PACKET_qXfer_threads,
|
||||
PACKET_qGetTLSAddr,
|
||||
PACKET_qSupported,
|
||||
PACKET_QPassSignals,
|
||||
@ -1395,7 +1411,7 @@ remote_notice_new_inferior (ptid_t currthread, int running)
|
||||
remote_add_thread (currthread, running);
|
||||
inferior_ptid = currthread;
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptid_equal (magic_null_ptid, inferior_ptid))
|
||||
@ -1405,7 +1421,7 @@ remote_notice_new_inferior (ptid_t currthread, int running)
|
||||
doesn't support qC. This is the first stop reported
|
||||
after an attach, so this is the main thread. Update the
|
||||
ptid in the thread list. */
|
||||
thread_change_ptid (inferior_ptid, currthread);
|
||||
thread_change_ptid (inferior_ptid, currthread);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1427,6 +1443,26 @@ remote_notice_new_inferior (ptid_t currthread, int running)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the private thread data, creating it if necessary. */
|
||||
|
||||
struct private_thread_info *
|
||||
demand_private_info (ptid_t ptid)
|
||||
{
|
||||
struct thread_info *info = find_thread_ptid (ptid);
|
||||
|
||||
gdb_assert (info);
|
||||
|
||||
if (!info->private)
|
||||
{
|
||||
info->private = xmalloc (sizeof (*(info->private)));
|
||||
info->private_dtor = free_private_thread_info;
|
||||
info->private->core = -1;
|
||||
info->private->extra = 0;
|
||||
}
|
||||
|
||||
return info->private;
|
||||
}
|
||||
|
||||
/* Call this function as a result of
|
||||
1) A halt indication (T packet) containing a thread id
|
||||
2) A direct query of currthread
|
||||
@ -1437,12 +1473,6 @@ static void
|
||||
record_currthread (ptid_t currthread)
|
||||
{
|
||||
general_thread = currthread;
|
||||
|
||||
if (ptid_equal (currthread, minus_one_ptid))
|
||||
/* We're just invalidating the local thread mirror. */
|
||||
return;
|
||||
|
||||
remote_notice_new_inferior (currthread, 0);
|
||||
}
|
||||
|
||||
static char *last_pass_packet;
|
||||
@ -2371,6 +2401,80 @@ remote_find_new_threads (void)
|
||||
CRAZY_MAX_THREADS);
|
||||
}
|
||||
|
||||
#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 thread_item item;
|
||||
char *id;
|
||||
|
||||
id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
|
||||
item.ptid = read_ptid (id, NULL);
|
||||
|
||||
if (VEC_length (gdb_xml_value_s, attributes) > 1)
|
||||
item.core = *(ULONGEST *) VEC_index (gdb_xml_value_s, attributes, 1)->value;
|
||||
else
|
||||
item.core = -1;
|
||||
|
||||
item.extra = 0;
|
||||
|
||||
VEC_safe_push (thread_item_t, data->items, &item);
|
||||
}
|
||||
|
||||
static void
|
||||
end_thread (struct gdb_xml_parser *parser,
|
||||
const struct gdb_xml_element *element,
|
||||
void *user_data, const char *body_text)
|
||||
{
|
||||
struct threads_parsing_context *data = user_data;
|
||||
|
||||
if (body_text && *body_text)
|
||||
VEC_last (thread_item_t, data->items)->extra = strdup (body_text);
|
||||
}
|
||||
|
||||
const struct gdb_xml_attribute thread_attributes[] = {
|
||||
{ "id", GDB_XML_AF_NONE, NULL, NULL },
|
||||
{ "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
|
||||
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element thread_children[] = {
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element threads_children[] = {
|
||||
{ "thread", thread_attributes, thread_children,
|
||||
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
|
||||
start_thread, end_thread },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
const struct gdb_xml_element threads_elements[] = {
|
||||
{ "threads", NULL, threads_children,
|
||||
GDB_XML_EF_NONE, NULL, NULL },
|
||||
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find all threads for info threads command.
|
||||
* Uses new thread protocol contributed by Cisco.
|
||||
@ -2388,6 +2492,61 @@ remote_threads_info (struct target_ops *ops)
|
||||
if (remote_desc == 0) /* paranoia */
|
||||
error (_("Command can only be used when connected to the remote target."));
|
||||
|
||||
#if defined(HAVE_LIBEXPAT)
|
||||
if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
|
||||
{
|
||||
char *xml = target_read_stralloc (¤t_target,
|
||||
TARGET_OBJECT_THREADS, NULL);
|
||||
|
||||
struct cleanup *back_to = make_cleanup (xfree, xml);
|
||||
if (xml && *xml)
|
||||
{
|
||||
struct gdb_xml_parser *parser;
|
||||
struct threads_parsing_context context;
|
||||
struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
|
||||
|
||||
context.items = 0;
|
||||
parser = gdb_xml_create_parser_and_cleanup (_("threads"),
|
||||
threads_elements,
|
||||
&context);
|
||||
|
||||
gdb_xml_use_dtd (parser, "threads.dtd");
|
||||
|
||||
if (gdb_xml_parse (parser, xml) == 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 = 0;
|
||||
}
|
||||
xfree (item->extra);
|
||||
}
|
||||
}
|
||||
|
||||
VEC_free (thread_item_t, context.items);
|
||||
}
|
||||
|
||||
do_cleanups (back_to);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (use_threadinfo_query)
|
||||
{
|
||||
putpkt ("qfThreadInfo");
|
||||
@ -2460,6 +2619,15 @@ remote_threads_extra_info (struct thread_info *tp)
|
||||
server doesn't know about it. */
|
||||
return NULL;
|
||||
|
||||
if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
|
||||
{
|
||||
struct thread_info *info = find_thread_ptid (tp->ptid);
|
||||
if (info && info->private)
|
||||
return info->private->extra;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (use_threadextra_query)
|
||||
{
|
||||
char *b = rs->buf;
|
||||
@ -3245,6 +3413,8 @@ static struct protocol_feature remote_protocol_features[] = {
|
||||
PACKET_qXfer_spu_write },
|
||||
{ "qXfer:osdata:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_osdata },
|
||||
{ "qXfer:threads:read", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_qXfer_threads },
|
||||
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
|
||||
PACKET_QPassSignals },
|
||||
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
|
||||
@ -4359,6 +4529,8 @@ struct stop_reply
|
||||
|
||||
int solibs_changed;
|
||||
int replay_event;
|
||||
|
||||
int core;
|
||||
};
|
||||
|
||||
/* The list of already fetched and acknowledged stop events. */
|
||||
@ -4522,6 +4694,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event)
|
||||
event->replay_event = 0;
|
||||
event->stopped_by_watchpoint_p = 0;
|
||||
event->regcache = NULL;
|
||||
event->core = -1;
|
||||
|
||||
switch (buf[0])
|
||||
{
|
||||
@ -4548,7 +4721,8 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event)
|
||||
/* If this packet is an awatch packet, don't parse the 'a'
|
||||
as a register number. */
|
||||
|
||||
if (strncmp (p, "awatch", strlen("awatch")) != 0)
|
||||
if (strncmp (p, "awatch", strlen("awatch")) != 0
|
||||
&& strncmp (p, "core", strlen ("core") != 0))
|
||||
{
|
||||
/* Read the ``P'' register number. */
|
||||
pnum = strtol (p, &p_temp, 16);
|
||||
@ -4594,6 +4768,12 @@ Packet: '%s'\n"),
|
||||
if (p_temp)
|
||||
p = p_temp;
|
||||
}
|
||||
else if (strncmp (p, "core", p1 - p) == 0)
|
||||
{
|
||||
ULONGEST c;
|
||||
p = unpack_varlen_hex (++p1, &c);
|
||||
event->core = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Silently skip unknown optional info. */
|
||||
@ -4803,6 +4983,7 @@ process_stop_reply (struct stop_reply *stop_reply,
|
||||
struct target_waitstatus *status)
|
||||
{
|
||||
ptid_t ptid;
|
||||
struct thread_info *info;
|
||||
|
||||
*status = stop_reply->ws;
|
||||
ptid = stop_reply->ptid;
|
||||
@ -4834,6 +5015,7 @@ process_stop_reply (struct stop_reply *stop_reply,
|
||||
remote_watch_data_address = stop_reply->watch_data_address;
|
||||
|
||||
remote_notice_new_inferior (ptid, 0);
|
||||
demand_private_info (ptid)->core = stop_reply->core;
|
||||
}
|
||||
|
||||
stop_reply_xfree (stop_reply);
|
||||
@ -7676,6 +7858,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
(ops, "osdata", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_osdata]);
|
||||
|
||||
case TARGET_OBJECT_THREADS:
|
||||
gdb_assert (annex == NULL);
|
||||
return remote_read_qxfer (ops, "threads", annex, readbuf, offset, len,
|
||||
&remote_protocol_packets[PACKET_qXfer_threads]);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -9324,6 +9511,15 @@ remote_set_disconnected_tracing (int val)
|
||||
error (_("Target does not support this command."));
|
||||
}
|
||||
|
||||
static int
|
||||
remote_core_of_thread (struct target_ops *ops, ptid_t ptid)
|
||||
{
|
||||
struct thread_info *info = find_thread_ptid (ptid);
|
||||
if (info && info->private)
|
||||
return info->private->core;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_remote_ops (void)
|
||||
{
|
||||
@ -9397,6 +9593,7 @@ Specify the serial device it is connected to\n\
|
||||
remote_ops.to_trace_find = remote_trace_find;
|
||||
remote_ops.to_get_trace_state_variable_value = remote_get_trace_state_variable_value;
|
||||
remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
|
||||
remote_ops.to_core_of_thread = remote_core_of_thread;
|
||||
}
|
||||
|
||||
/* Set up the extended remote vector by making a copy of the standard
|
||||
@ -9933,6 +10130,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata],
|
||||
"qXfer:osdata:read", "osdata", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_threads],
|
||||
"qXfer:threads:read", "threads", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_read],
|
||||
"qXfer:siginfo:read", "read-siginfo-object", 0);
|
||||
|
||||
|
Reference in New Issue
Block a user