range stepping: gdbserver (x86 GNU/Linux)
[deliverable/binutils-gdb.git] / gdb / gdbserver / server.c
index 768eae7f3d1dfb87b258150bf1661ec2ea4580ae..1083aa9e56e08a0c2895f1005531a6622cce3523 100644 (file)
@@ -28,6 +28,7 @@
 #include <signal.h>
 #endif
 #include "gdb_wait.h"
+#include "btrace-common.h"
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -396,6 +397,88 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
                               PBUFSIZ - 2) + 1;
 }
 
+/* Handle btrace enabling.  */
+
+static const char *
+handle_btrace_enable (struct thread_info *thread)
+{
+  if (thread->btrace != NULL)
+    return "E.Btrace already enabled.";
+
+  thread->btrace = target_enable_btrace (thread->entry.id);
+  if (thread->btrace == NULL)
+    return "E.Could not enable btrace.";
+
+  return NULL;
+}
+
+/* Handle btrace disabling.  */
+
+static const char *
+handle_btrace_disable (struct thread_info *thread)
+{
+
+  if (thread->btrace == NULL)
+    return "E.Branch tracing not enabled.";
+
+  if (target_disable_btrace (thread->btrace) != 0)
+    return "E.Could not disable branch tracing.";
+
+  thread->btrace = NULL;
+  return NULL;
+}
+
+/* Handle the "Qbtrace" packet.  */
+
+static int
+handle_btrace_general_set (char *own_buf)
+{
+  struct thread_info *thread;
+  const char *err;
+  char *op;
+
+  if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0)
+    return 0;
+
+  op = own_buf + strlen ("Qbtrace:");
+
+  if (!target_supports_btrace ())
+    {
+      strcpy (own_buf, "E.Target does not support branch tracing.");
+      return -1;
+    }
+
+  if (ptid_equal (general_thread, null_ptid)
+      || ptid_equal (general_thread, minus_one_ptid))
+    {
+      strcpy (own_buf, "E.Must select a single thread.");
+      return -1;
+    }
+
+  thread = find_thread_ptid (general_thread);
+  if (thread == NULL)
+    {
+      strcpy (own_buf, "E.No such thread.");
+      return -1;
+    }
+
+  err = NULL;
+
+  if (strcmp (op, "bts") == 0)
+    err = handle_btrace_enable (thread);
+  else if (strcmp (op, "off") == 0)
+    err = handle_btrace_disable (thread);
+  else
+    err = "E.Bad Qbtrace operation. Use bts or off.";
+
+  if (err != 0)
+    strcpy (own_buf, err);
+  else
+    write_ok (own_buf);
+
+  return 1;
+}
+
 /* Handle all of the extended 'Q' packets.  */
 
 static void
@@ -552,6 +635,9 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (handle_btrace_general_set (own_buf))
+    return;
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -892,10 +978,10 @@ struct qxfer
      data-specific information to the target.
 
      Return the number of bytes actually transfered, zero when no
-     further transfer is possible, -1 on error, and -2 when the
-     transfer is not supported.  Return of a positive value smaller
-     than LEN does not indicate the end of the object, only the end of
-     the transfer.
+     further transfer is possible, -1 on error, -2 when the transfer
+     is not supported, and -3 on a verbose error message that should
+     be preserved.  Return of a positive value smaller than LEN does
+     not indicate the end of the object, only the end of the transfer.
 
      One, and only one, of readbuf or writebuf must be non-NULL.  */
   int (*xfer) (const char *annex,
@@ -1251,9 +1337,77 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
   return (*the_target->read_loadmap) (annex, offset, readbuf, len);
 }
 
+/* Handle qXfer:btrace:read.  */
+
+static int
+handle_qxfer_btrace (const char *annex,
+                    gdb_byte *readbuf, const gdb_byte *writebuf,
+                    ULONGEST offset, LONGEST len)
+{
+  static struct buffer cache;
+  struct thread_info *thread;
+  int type;
+
+  if (the_target->read_btrace == NULL || writebuf != NULL)
+    return -2;
+
+  if (!target_running ())
+    return -1;
+
+  if (ptid_equal (general_thread, null_ptid)
+      || ptid_equal (general_thread, minus_one_ptid))
+    {
+      strcpy (own_buf, "E.Must select a single thread.");
+      return -3;
+    }
+
+  thread = find_thread_ptid (general_thread);
+  if (thread == NULL)
+    {
+      strcpy (own_buf, "E.No such thread.");
+      return -3;
+    }
+
+  if (thread->btrace == NULL)
+    {
+      strcpy (own_buf, "E.Btrace not enabled.");
+      return -3;
+    }
+
+  if (strcmp (annex, "all") == 0)
+    type = btrace_read_all;
+  else if (strcmp (annex, "new") == 0)
+    type = btrace_read_new;
+  else
+    {
+      strcpy (own_buf, "E.Bad annex.");
+      return -3;
+    }
+
+  if (offset == 0)
+    {
+      buffer_free (&cache);
+
+      target_read_btrace (thread->btrace, &cache, type);
+    }
+  else if (offset > cache.used_size)
+    {
+      buffer_free (&cache);
+      return -3;
+    }
+
+  if (len > cache.used_size - offset)
+    len = cache.used_size - offset;
+
+  memcpy (readbuf, cache.buffer + offset, len);
+
+  return len;
+}
+
 static const struct qxfer qxfer_packets[] =
   {
     { "auxv", handle_qxfer_auxv },
+    { "btrace", handle_qxfer_btrace },
     { "fdpic", handle_qxfer_fdpic},
     { "features", handle_qxfer_features },
     { "libraries", handle_qxfer_libraries },
@@ -1323,6 +1477,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p)
                  free (data);
                  return 0;
                }
+             else if (n == -3)
+               {
+                 /* Preserve error message.  */
+               }
              else if (n < 0)
                write_enn (own_buf);
              else if (n > len)
@@ -1361,6 +1519,10 @@ handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p)
                  free (data);
                  return 0;
                }
+             else if (n == -3)
+               {
+                 /* Preserve error message.  */
+               }
              else if (n < 0)
                write_enn (own_buf);
              else
@@ -1637,6 +1799,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
          strcat (own_buf, ";qXfer:statictrace:read+");
          strcat (own_buf, ";qXfer:traceframe-info:read+");
          strcat (own_buf, ";EnableDisableTracepoints+");
+         strcat (own_buf, ";QTBuffer:size+");
          strcat (own_buf, ";tracenz+");
        }
 
@@ -1647,6 +1810,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (target_supports_agent ())
        strcat (own_buf, ";QAgent+");
 
+      if (target_supports_btrace ())
+       {
+         strcat (own_buf, ";Qbtrace:bts+");
+         strcat (own_buf, ";Qbtrace:off+");
+         strcat (own_buf, ";qXfer:btrace:read+");
+       }
+
       return;
     }
 
@@ -1872,8 +2042,12 @@ handle_v_cont (char *own_buf)
     {
       p++;
 
+      memset (&resume_info[i], 0, sizeof resume_info[i]);
+
       if (p[0] == 's' || p[0] == 'S')
        resume_info[i].kind = resume_step;
+      else if (p[0] == 'r')
+       resume_info[i].kind = resume_step;
       else if (p[0] == 'c' || p[0] == 'C')
        resume_info[i].kind = resume_continue;
       else if (p[0] == 't')
@@ -1893,9 +2067,22 @@ handle_v_cont (char *own_buf)
            goto err;
          resume_info[i].sig = gdb_signal_to_host (sig);
        }
+      else if (p[0] == 'r')
+       {
+         char *p1;
+
+         p = p + 1;
+         p1 = strchr (p, ',');
+         decode_address (&resume_info[i].step_range_start, p, p1 - p);
+
+         p = p1 + 1;
+         p1 = strchr (p, ':');
+         decode_address (&resume_info[i].step_range_end, p, p1 - p);
+
+         p = p1;
+       }
       else
        {
-         resume_info[i].sig = 0;
          p = p + 1;
        }
 
@@ -2141,6 +2328,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
       if (strncmp (own_buf, "vCont?", 6) == 0)
        {
          strcpy (own_buf, "vCont;c;C;s;S;t");
+         if (target_supports_range_stepping ())
+           {
+             own_buf = own_buf + strlen (own_buf);
+             strcpy (own_buf, ";r");
+           }
          return;
        }
     }
This page took 0.028354 seconds and 4 git commands to generate.