+ return remote_escape_output (data, len, 1, (unsigned char *) buf + 1,
+ &out_len, PBUFSIZ - 2) + 1;
+}
+
+/* Handle btrace enabling in BTS format. */
+
+static const char *
+handle_btrace_enable_bts (struct thread_info *thread)
+{
+ if (thread->btrace != NULL)
+ return "E.Btrace already enabled.";
+
+ current_btrace_conf.format = BTRACE_FORMAT_BTS;
+ thread->btrace = target_enable_btrace (thread->entry.id,
+ ¤t_btrace_conf);
+ if (thread->btrace == NULL)
+ return "E.Could not enable btrace.";
+
+ return NULL;
+}
+
+/* Handle btrace enabling in Intel Processor Trace format. */
+
+static const char *
+handle_btrace_enable_pt (struct thread_info *thread)
+{
+ if (thread->btrace != NULL)
+ return "E.Btrace already enabled.";
+
+ current_btrace_conf.format = BTRACE_FORMAT_PT;
+ thread->btrace = target_enable_btrace (thread->entry.id,
+ ¤t_btrace_conf);
+ 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 (!startswith (own_buf, "Qbtrace:"))
+ return 0;
+
+ op = own_buf + strlen ("Qbtrace:");
+
+ 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_bts (thread);
+ else if (strcmp (op, "pt") == 0)
+ err = handle_btrace_enable_pt (thread);
+ else if (strcmp (op, "off") == 0)
+ err = handle_btrace_disable (thread);
+ else
+ err = "E.Bad Qbtrace operation. Use bts, pt, or off.";
+
+ if (err != 0)
+ strcpy (own_buf, err);
+ else
+ write_ok (own_buf);
+
+ return 1;
+}
+
+/* Handle the "Qbtrace-conf" packet. */
+
+static int
+handle_btrace_conf_general_set (char *own_buf)
+{
+ struct thread_info *thread;
+ char *op;
+
+ if (!startswith (own_buf, "Qbtrace-conf:"))
+ return 0;
+
+ op = own_buf + strlen ("Qbtrace-conf:");
+
+ 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;
+ }
+
+ if (startswith (op, "bts:size="))
+ {
+ unsigned long size;
+ char *endp = NULL;
+
+ errno = 0;
+ size = strtoul (op + strlen ("bts:size="), &endp, 16);
+ if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX)
+ {
+ strcpy (own_buf, "E.Bad size value.");
+ return -1;
+ }
+
+ current_btrace_conf.bts.size = (unsigned int) size;
+ }
+ else if (strncmp (op, "pt:size=", strlen ("pt:size=")) == 0)
+ {
+ unsigned long size;
+ char *endp = NULL;
+
+ errno = 0;
+ size = strtoul (op + strlen ("pt:size="), &endp, 16);
+ if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX)
+ {
+ strcpy (own_buf, "E.Bad size value.");
+ return -1;
+ }
+
+ current_btrace_conf.pt.size = (unsigned int) size;
+ }
+ else
+ {
+ strcpy (own_buf, "E.Bad Qbtrace configuration option.");
+ return -1;
+ }
+
+ write_ok (own_buf);
+ return 1;