Display names of remote threads
authorSimon Marchi <simon.marchi@ericsson.com>
Thu, 26 Nov 2015 14:49:04 +0000 (09:49 -0500)
committerSimon Marchi <simon.marchi@ericsson.com>
Thu, 26 Nov 2015 15:50:08 +0000 (10:50 -0500)
This patch adds support for thread names in the remote protocol, and
updates gdb/gdbserver to use it.  The information is added to the XML
description sent in response to the qXfer:threads:read packet.

gdb/ChangeLog:

* 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.

gdb/gdbserver/ChangeLog:

* 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.

gdb/doc/ChangeLog:

* gdb.texinfo (Thread List Format): Mention thread names.

13 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/server.c
gdb/gdbserver/target.h
gdb/linux-nat.c
gdb/nat/linux-procfs.c
gdb/nat/linux-procfs.h
gdb/remote.c
gdb/target.h

index 1d9cb4f975ac95440d49b60aa36da94cacc0aabb..0871500f3f39b326e534045bbb8d3d5fbe436b0e 100644 (file)
@@ -1,3 +1,23 @@
+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.
index 31072b7fd3edda87699e706f75ac355f9489482c..5f704fe472cb709603f276fbe2ee74b735f74361 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -94,6 +94,11 @@ set remote exec-event-feature-packet
 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*
index 80df9ad2a12992ad90bd3266340baa96d01629ae..7e747dcf8b4bf72cac12a6f46a98f9e3ea50c282 100644 (file)
@@ -1,3 +1,7 @@
+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
index 1917008adee40b5241035bbd8e4bb16fbb5acdbc..c4d8a186774d96d14222f2aeb024ed1886ff21ad 100644 (file)
@@ -39542,7 +39542,7 @@ the following structure:
 @smallexample
 <?xml version="1.0"?>
 <threads>
-    <thread id="id" core="0">
+    <thread id="id" core="0" name="name">
     ... description ...
     </thread>
 </threads>
@@ -39551,8 +39551,10 @@ the following structure:
 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
index e265798a3ce0774cf5095faaedd2ed2c95368066..6e2a95d749eeb99e7d053b19ea2c9cbf0019973d 100644 (file)
@@ -1,3 +1,12 @@
+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.
index e3a56a7c1690c18ecf44b26434087d4f3ced55ce..a70868c787d36d0cb06ead08aef76a07b958428b 100644 (file)
@@ -7043,7 +7043,8 @@ static struct target_ops linux_target_ops = {
   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
index 7d6c9cc47a2514d79efb7ec2e0b28380cd36539e..0105b994fb2b2262e4cc87886bdf60f3bc0ec917 100644 (file)
@@ -1456,20 +1456,22 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
   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.  */
index 358a8ab77a8307fa2aced2e65990648006b8302b..8903da59e8deb2937d790b1c7cc82294896623f8 100644 (file)
@@ -453,6 +453,10 @@ struct target_ops
      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;
@@ -663,6 +667,10 @@ ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
   (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,
index 24216876c247ba4dbd5109a1e5abde81ce950bc9..9bc132467c37f536e48aa28acb31fd388770f88a 100644 (file)
@@ -4100,38 +4100,7 @@ linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
 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
index 24bcb019a398f81e9a6c5ccf624147f97a05629e..78cbb03cb215a4aec1bd595d3408696276e9a7c9 100644 (file)
@@ -187,6 +187,48 @@ linux_proc_pid_is_zombie (pid_t pid)
 
 /* 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)
index f9cad39562c66bd92f275328b6192f15538ff30a..f28c1ba344e6c397d608d1e0cfef161166f1679e 100644 (file)
@@ -54,6 +54,13 @@ extern int linux_proc_pid_is_zombie_nowarn (pid_t pid);
 
 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.  */
index 2bbab624b25de95e2446dc0be258a147602d48a6..a80e548d9f8246368dc5f799a4bc24cbdd9e30a9 100644 (file)
@@ -437,6 +437,7 @@ struct remote_state
 struct private_thread_info
 {
   char *extra;
+  char *name;
   int core;
 };
 
@@ -444,6 +445,7 @@ static void
 free_private_thread_info (struct private_thread_info *info)
 {
   xfree (info->extra);
+  xfree (info->name);
   xfree (info);
 }
 
@@ -2141,6 +2143,18 @@ remote_thread_alive (struct target_ops *ops, ptid_t ptid)
   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
@@ -2821,6 +2835,9 @@ typedef struct thread_item
   /* 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;
@@ -2847,7 +2864,10 @@ clear_threads_listing_context (void *p)
   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);
 }
@@ -2951,6 +2971,9 @@ start_thread (struct gdb_xml_parser *parser,
   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);
@@ -2971,6 +2994,7 @@ end_thread (struct gdb_xml_parser *parser,
 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 }
 };
 
@@ -3149,6 +3173,8 @@ remote_update_thread_list (struct target_ops *ops)
              info->core = item->core;
              info->extra = item->extra;
              item->extra = NULL;
+             info->name = item->name;
+             item->name = NULL;
            }
        }
     }
@@ -12738,6 +12764,7 @@ Specify the serial device it is connected to\n\
   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;
index ac28a4169d989c3c5d01def41d30918fdf7fbd07..65b717c730889f25b8a305ec2371cfb78e647009 100644 (file)
@@ -1820,8 +1820,8 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_extra_thread_info(TP) \
      (current_target.to_extra_thread_info (&current_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 *);