+2015-11-26 Daniel Colascione <dancol@dancol.org>
+2015-11-26 Simon Marchi <simon.marchi@ericsson.com>
+
+ * linux-nat.c (linux_nat_thread_name): Replace implementation by call
+ to linux_proc_tid_get_name.
+ * nat/linux-procfs.c (linux_proc_tid_get_name): New function,
+ implementation inspired by linux_nat_thread_name.
+ * nat/linux-procfs.h (linux_proc_tid_get_name): New declaration.
+ * remote.c (struct private_thread_info) <name>: New field.
+ (free_private_thread_info): Free name field.
+ (remote_thread_name): New function.
+ (thread_item_t) <name>: New field.
+ (clear_threads_listing_context): Free name field.
+ (start_thread): Get name xml attribute.
+ (thread_attributes): Add "name" attribute.
+ (remote_update_thread_list): Copy name field.
+ (init_remote_ops): Assign remote_thread_name callback.
+ * target.h (target_thread_name): Update comment.
+ * NEWS: Mention remote thread name support.
+
2015-11-26 Simon Marchi <simon.marchi@ericsson.com>
* linux-nat.c (linux_nat_thread_name): Constify return value.
show remote exec-event-feature-packet
Set/show the use of the remote exec event feature.
+ * Thread names in remote protocol
+
+ The reply to qXfer:threads:read may now include a name attribute for each
+ thread.
+
*** Changes in GDB 7.10
* Support for process record-replay and reverse debugging on aarch64*-linux*
+2015-11-26 Simon Marchi <simon.marchi@ericsson.com>
+
+ * gdb.texinfo (Thread List Format): Mention thread names.
+
2015-11-24 Pedro Alves <palves@redhat.com>
PR 17539
@smallexample
<?xml version="1.0"?>
<threads>
- <thread id="id" core="0">
+ <thread id="id" core="0" name="name">
... description ...
</thread>
</threads>
Each @samp{thread} element must have the @samp{id} attribute that
identifies the thread (@pxref{thread-id syntax}). The
@samp{core} attribute, if present, specifies which processor core
-the thread was last executing on. The content of the of @samp{thread}
-element is interpreted as human-readable auxilliary information.
+the thread was last executing on. The @samp{name} attribute, if
+present, specifies the human-readable name of the thread. The content
+of the of @samp{thread} element is interpreted as human-readable
+auxiliary information.
@node Traceframe Info Format
@section Traceframe Info Format
+2015-11-26 Daniel Colascione <dancol@dancol.org>
+2015-11-26 Simon Marchi <simon.marchi@ericsson.com>
+
+ * linux-low.c (linux_target_ops): Use linux_proc_tid_get_name.
+ * server.c (handle_qxfer_threads_worker): Refactor to include thread
+ name in reply.
+ * target.h (struct target_ops) <thread_name>: New field.
+ (target_thread_name): New macro.
+
2015-11-23 Joel Brobecker <brobecker@adacore.com>
* regcache.h (regcache_invalidate_pid): Add declaration.
linux_mntns_unlink,
linux_mntns_readlink,
linux_breakpoint_kind_from_pc,
- linux_sw_breakpoint_from_kind
+ linux_sw_breakpoint_from_kind,
+ linux_proc_tid_get_name,
};
static void
char ptid_s[100];
int core = target_core_of_thread (ptid);
char core_s[21];
+ const char *name = target_thread_name (ptid);
write_ptid (ptid_s, ptid);
+ buffer_xml_printf (buffer, "<thread id=\"%s\"", ptid_s);
+
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_xml_printf (buffer, " core=\"%s\"", core_s);
}
+
+ if (name != NULL)
+ buffer_xml_printf (buffer, " name=\"%s\"", name);
+
+ buffer_xml_printf (buffer, "/>\n");
}
/* Helper for handle_qxfer_threads. */
specific meaning like the Z0 kind parameter.
SIZE is set to the software breakpoint's length in memory. */
const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
+
+ /* Return the thread's name, or NULL if the target is unable to determine it.
+ The returned value must not be freed by the caller. */
+ const char *(*thread_name) (ptid_t thread);
};
extern struct target_ops *the_target;
(the_target->core_of_thread ? (*the_target->core_of_thread) (ptid) \
: -1)
+#define target_thread_name(ptid) \
+ (the_target->thread_name ? (*the_target->thread_name) (ptid) \
+ : NULL)
+
int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
static const char *
linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
{
- int pid = ptid_get_pid (thr->ptid);
- long lwp = ptid_get_lwp (thr->ptid);
-#define FORMAT "/proc/%d/task/%ld/comm"
- char buf[sizeof (FORMAT) + 30];
- FILE *comm_file;
- char *result = NULL;
-
- snprintf (buf, sizeof (buf), FORMAT, pid, lwp);
- comm_file = gdb_fopen_cloexec (buf, "r");
- if (comm_file)
- {
- /* Not exported by the kernel, so we define it here. */
-#define COMM_LEN 16
- static char line[COMM_LEN + 1];
-
- if (fgets (line, sizeof (line), comm_file))
- {
- char *nl = strchr (line, '\n');
-
- if (nl)
- *nl = '\0';
- if (*line != '\0')
- result = line;
- }
-
- fclose (comm_file);
- }
-
-#undef COMM_LEN
-#undef FORMAT
-
- return result;
+ return linux_proc_tid_get_name (thr->ptid);
}
/* Accepts an integer PID; Returns a string representing a file that
/* See linux-procfs.h. */
+const char *
+linux_proc_tid_get_name (ptid_t ptid)
+{
+#define TASK_COMM_LEN 16 /* As defined in the kernel's sched.h. */
+
+ static char comm_buf[TASK_COMM_LEN];
+ char comm_path[100];
+ FILE *comm_file;
+ const char *comm_val;
+ pid_t pid = ptid_get_pid (ptid);
+ pid_t tid = ptid_lwp_p (ptid) ? ptid_get_lwp (ptid) : ptid_get_pid (ptid);
+
+ xsnprintf (comm_path, sizeof (comm_path),
+ "/proc/%ld/task/%ld/comm", (long) pid, (long) tid);
+
+ comm_file = gdb_fopen_cloexec (comm_path, "r");
+ if (comm_file == NULL)
+ return NULL;
+
+ comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file);
+ fclose (comm_file);
+
+ if (comm_val != NULL)
+ {
+ int i;
+
+ /* Make sure there is no newline at the end. */
+ for (i = 0; i < sizeof (comm_buf); i++)
+ {
+ if (comm_buf[i] == '\n')
+ {
+ comm_buf[i] = '\0';
+ break;
+ }
+ }
+ }
+
+ return comm_val;
+}
+
+/* See linux-procfs.h. */
+
void
linux_proc_attach_tgid_threads (pid_t pid,
linux_proc_attach_lwp_func attach_lwp)
extern int linux_proc_pid_is_gone (pid_t pid);
+/* Return a string giving the thread's name or NULL if the
+ information is unavailable. The returned value points to a statically
+ allocated buffer. The value therefore becomes invalid at the next
+ linux_proc_tid_get_name call. */
+
+extern const char *linux_proc_tid_get_name (ptid_t ptid);
+
/* Callback function for linux_proc_attach_tgid_threads. If the PTID
thread is not yet known, try to attach to it and return true,
otherwise return false. */
struct private_thread_info
{
char *extra;
+ char *name;
int core;
};
free_private_thread_info (struct private_thread_info *info)
{
xfree (info->extra);
+ xfree (info->name);
xfree (info);
}
return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
}
+/* Return a pointer to a thread name if we know it and NULL otherwise.
+ The thread_info object owns the memory for the name. */
+
+static const char *
+remote_thread_name (struct target_ops *ops, struct thread_info *info)
+{
+ if (info->priv != NULL)
+ return info->priv->name;
+
+ return NULL;
+}
+
/* About these extended threadlist and threadinfo packets. They are
variable length packets but, the fields within them are often fixed
length. They are redundent enough to send over UDP as is the
/* The thread's extra info. May be NULL. */
char *extra;
+ /* The thread's name. May be NULL. */
+ char *name;
+
/* The core the thread was running on. -1 if not known. */
int core;
} thread_item_t;
struct thread_item *item;
for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
- xfree (item->extra);
+ {
+ xfree (item->extra);
+ xfree (item->name);
+ }
VEC_free (thread_item_t, context->items);
}
else
item.core = -1;
+ attr = xml_find_attribute (attributes, "name");
+ item.name = attr != NULL ? xstrdup (attr->value) : NULL;
+
item.extra = 0;
VEC_safe_push (thread_item_t, data->items, &item);
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 },
+ { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
info->core = item->core;
info->extra = item->extra;
item->extra = NULL;
+ info->name = item->name;
+ item->name = NULL;
}
}
}
remote_ops.to_pass_signals = remote_pass_signals;
remote_ops.to_program_signals = remote_program_signals;
remote_ops.to_thread_alive = remote_thread_alive;
+ remote_ops.to_thread_name = remote_thread_name;
remote_ops.to_update_thread_list = remote_update_thread_list;
remote_ops.to_pid_to_str = remote_pid_to_str;
remote_ops.to_extra_thread_info = remote_threads_extra_info;
#define target_extra_thread_info(TP) \
(current_target.to_extra_thread_info (¤t_target, TP))
-/* Return the thread's name. A NULL result means that the target
- could not determine this thread's name. */
+/* Return the thread's name, or NULL if the target is unable to determine it.
+ The returned value must not be freed by the caller. */
extern const char *target_thread_name (struct thread_info *);