This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 15/17] gdbserver, btrace: add generic btrace support
- From: markus dot t dot metzger at intel dot com
- To: jan dot kratochvil at redhat dot com
- Cc: gdb-patches at sourceware dot org, markus dot t dot metzger at gmail dot com, Markus Metzger <markus dot t dot metzger at intel dot com>
- Date: Wed, 6 Jun 2012 14:32:33 +0200
- Subject: [PATCH 15/17] gdbserver, btrace: add generic btrace support
- References: <1338985955-28749-1-git-send-email-markus.t.metzger@intel.com>
From: Markus Metzger <markus.t.metzger@intel.com>
Add support to gdbserver to understand branch trace related packages.
2012-06-06 Markus Metzger <markus.t.metzger@intel.com>
gdb/gdbserver/
* target.h (struct target_ops): Add btrace ops.
(target_supports_btrace): New macro.
(target_btrace_has_changed): New macro.
(target_enable_btrace): New macro.
(target_disable_btrace): New macro.
(target_read_btrace): New macro.
* gdbthread.h (struct thread_info): Add btrace field.
* server.c (handle_btrace_general_set): New function.
(handle_btrace_enable): New function.
(handle_btrace_disable): New function.
(handle_general_set): Call handle_btrace_general_set.
(handle_qxfer_btrace): New function.
(struct qxfer qxfer_packets[]): Add btrace entry.
(handle_btrace_query): New function.
(handle_query): Add btrace to supported query, call handle_btrace_query.
* inferiors.c (remove_thread): Disable btrace.
---
gdb/gdbserver/gdbthread.h | 5 ++
gdb/gdbserver/inferiors.c | 3 +
gdb/gdbserver/server.c | 167 +++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbserver/target.h | 33 +++++++++
4 files changed, 208 insertions(+), 0 deletions(-)
diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index d863ec0..b2b6f62 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -22,6 +22,8 @@
#include "server.h"
+struct btrace_target_info;
+
struct thread_info
{
struct inferior_list_entry entry;
@@ -58,6 +60,9 @@ struct thread_info
Each item in the list holds the current step of the while-stepping
action. */
struct wstep_state *while_stepping;
+
+ /* Branch trace target information for this thread. */
+ struct btrace_target_info *btrace;
};
extern struct inferior_list all_threads;
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index 76abaf5..76f5731 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -161,6 +161,9 @@ free_one_thread (struct inferior_list_entry *inf)
void
remove_thread (struct thread_info *thread)
{
+ if (thread->btrace)
+ target_disable_btrace (thread->btrace);
+
remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
free_one_thread (&thread->entry);
}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 9fd550b..2e78c67 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -446,6 +446,82 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
/* Handle all of the extended 'Q' packets. */
+/* Handle btrace enabling. */
+static int
+handle_btrace_enable (char *ptid_str)
+{
+ ptid_t ptid = read_ptid (ptid_str, NULL);
+ struct thread_info *thread = find_thread_ptid (ptid);
+ int err = 1;
+
+ if (!thread)
+ fprintf (stderr, "No such thread: %s.\n", ptid_str);
+ else if (thread->btrace)
+ fprintf (stderr, "Btrace already enabled for %s.\n", ptid_str);
+ else if (!the_target->enable_btrace)
+ fprintf (stderr, "Target does not support branch tracing.");
+ else
+ {
+ thread->btrace = target_enable_btrace (thread->entry.id);
+ if (!thread->btrace)
+ fprintf (stderr, "Could not enable btrace for %s.\n", ptid_str);
+ else
+ err = 0;
+ }
+
+ return err;
+}
+
+/* Handle btrace disabling. */
+static int
+handle_btrace_disable (char *ptid_str)
+{
+ ptid_t ptid = read_ptid (ptid_str, NULL);
+ struct thread_info *thread = find_thread_ptid (ptid);
+ int err = 1;
+
+ if (!thread)
+ fprintf (stderr, "No such thread: %s.\n", ptid_str);
+ else if (!thread->btrace)
+ fprintf (stderr, "Branch tracing not enabled for %s.\n", ptid_str);
+ else if (!the_target->disable_btrace)
+ fprintf (stderr, "Target does not support branch tracing.");
+ else if (target_disable_btrace (thread->btrace) != 0)
+ fprintf (stderr, "Could not disable branch tracing for %s.\n", ptid_str);
+ else
+ {
+ thread->btrace = NULL;
+ err = 0;
+ }
+
+ return err;
+}
+
+/* Handle the "Qbtrace" packet. */
+static int
+handle_btrace_general_set (char *own_buf)
+{
+ char *operation = own_buf + strlen ("Qbtrace:");
+ int err = 1;
+
+ if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0)
+ return 0;
+
+ if (strncmp ("on:", operation, strlen ("on:")) == 0)
+ err = handle_btrace_enable (operation + strlen ("on:"));
+ else if (strncmp ("off:", operation, strlen ("off:")) == 0)
+ err = handle_btrace_disable (operation + strlen ("off:"));
+ else
+ fprintf (stderr, "Unknown btrace operation: %s. Use on or off.\n", own_buf);
+
+ if (err)
+ write_enn (own_buf);
+ else
+ write_ok (own_buf);
+
+ return 1;
+}
+
static void
handle_general_set (char *own_buf)
{
@@ -600,6 +676,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;
@@ -1298,6 +1377,55 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
return (*the_target->read_loadmap) (annex, offset, readbuf, len);
}
+/* Handle branch trace data transfer. */
+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;
+ ptid_t ptid;
+
+ if (!the_target->read_btrace || writebuf)
+ return -2;
+
+ if (!target_running () || !annex)
+ return -1;
+
+ ptid = read_ptid ((char *) annex, NULL);
+ thread = find_thread_ptid (ptid);
+ if (!thread)
+ {
+ fprintf (stderr, "No such thread: %s\n", annex);
+ return -1;
+ }
+ else if (!thread->btrace)
+ {
+ fprintf (stderr, "Btrace not enabled for %s\n", annex);
+ return -1;
+ }
+
+ if (!offset)
+ {
+ buffer_free (&cache);
+
+ target_read_btrace (thread->btrace, &cache);
+ }
+ else if (offset >= cache.used_size)
+ {
+ buffer_free (&cache);
+ return 0;
+ }
+
+ 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 },
@@ -1311,6 +1439,7 @@ static const struct qxfer qxfer_packets[] =
{ "statictrace", handle_qxfer_statictrace },
{ "threads", handle_qxfer_threads },
{ "traceframe-info", handle_qxfer_traceframe_info },
+ { "btrace", handle_qxfer_btrace },
};
static int
@@ -1467,6 +1596,34 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
/* Handle all of the extended 'q' packets. */
+/* Handle the "qbtrace" packet. */
+static int
+handle_btrace_query (char *own_buf)
+{
+ if (strncmp ("qbtrace:", own_buf, strlen ("qbtrace:")) == 0)
+ {
+ char *ptid_str = own_buf + strlen ("qbtrace:");
+ ptid_t ptid = read_ptid (ptid_str, NULL);
+ struct thread_info *thread = find_thread_ptid (ptid);
+
+ if (!thread)
+ {
+ fprintf (stderr, "No such thread: %s\n", ptid_str);
+ write_enn (own_buf);
+ }
+ else if (!thread->btrace)
+ {
+ fprintf (stderr, "Btrace not enabled for %s\n", ptid_str);
+ write_enn (own_buf);
+ }
+ else
+ strcpy (own_buf,
+ (target_btrace_has_changed (thread->btrace) ? "yes" : "no"));
+ return 1;
+ }
+ return 0;
+}
+
void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
@@ -1693,6 +1850,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+");
+ strcat (own_buf, ";Qbtrace+");
+ strcat (own_buf, ";qXfer:btrace:read+");
+ }
+
return;
}
@@ -1883,6 +2047,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
return;
+ if (handle_btrace_query (own_buf))
+ return;
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 0cf5687..9adaeca 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -22,6 +22,8 @@
#define TARGET_H
struct emit_ops;
+struct btrace_target_info;
+struct buffer;
/* Ways to "resume" a thread. */
@@ -397,6 +399,22 @@ struct target_ops
/* Return true if target supports debugging agent. */
int (*supports_agent) (void);
+
+ /* Check whether the target supports branch tracing. */
+ int (*supports_btrace) (void);
+
+ /* Enable branch tracing for @ptid and allocate a branch trace target
+ information struct for reading and for disabling branch trace. */
+ struct btrace_target_info *(*enable_btrace) (ptid_t ptid);
+
+ /* Disable branch tracing. */
+ int (*disable_btrace) (struct btrace_target_info *tinfo);
+
+ /* Check whether branch trace changed on the target. */
+ int (*btrace_has_changed) (struct btrace_target_info *);
+
+ /* Read branch trace data into buffer. */
+ void (*read_btrace) (struct btrace_target_info *, struct buffer *);
};
extern struct target_ops *the_target;
@@ -521,6 +539,21 @@ void set_target_ops (struct target_ops *);
(the_target->supports_agent ? \
(*the_target->supports_agent) () : 0)
+#define target_supports_btrace() \
+ (the_target->supports_btrace ? (*the_target->supports_btrace) () : 0)
+
+#define target_enable_btrace(ptid) \
+ (*the_target->enable_btrace) (ptid)
+
+#define target_disable_btrace(tinfo) \
+ (*the_target->disable_btrace) (tinfo)
+
+#define target_btrace_has_changed(tinfo) \
+ (*the_target->btrace_has_changed) (tinfo)
+
+#define target_read_btrace(tinfo, buffer) \
+ (*the_target->read_btrace) (tinfo, buffer)
+
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);
--
1.7.1