This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch v9 07/23] gdbserver, btrace: add generic btrace support
- From: Markus Metzger <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
- Date: Mon, 4 Mar 2013 18:05:54 +0100
- Subject: [patch v9 07/23] gdbserver, btrace: add generic btrace support
- References: <1362416770-19750-1-git-send-email-markus.t.metzger@intel.com>
Add support to gdbserver to understand branch trace related packages.
2013-03-04 Markus Metzger <markus.t.metzger@intel.com>
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 | 188 +++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbserver/target.h | 33 ++++++++
4 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 85951d2..5d4955b 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -21,6 +21,8 @@
#include "server.h"
+struct btrace_target_info;
+
struct thread_info
{
struct inferior_list_entry entry;
@@ -57,6 +59,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 ba3c6cd..6953d0e 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 != NULL)
+ 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 768eae7..e755ba0 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -396,6 +396,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, "on") == 0)
+ err = handle_btrace_enable (thread);
+ else if (strcmp (op, "off") == 0)
+ err = handle_btrace_disable (thread);
+ else
+ err = "E.Bad Qbtrace operation. Use on 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 +634,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;
@@ -1251,9 +1336,66 @@ 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;
+
+ if (the_target->read_btrace == NULL || writebuf != NULL)
+ return -2;
+
+ if (!target_running () || annex[0] != '\0')
+ 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;
+ }
+
+ if (thread->btrace == NULL)
+ {
+ strcpy (own_buf, "E.Btrace not enabled.");
+ return -1;
+ }
+
+ if (offset == 0)
+ {
+ buffer_free (&cache);
+
+ target_read_btrace (thread->btrace, &cache);
+ }
+ else if (offset > cache.used_size)
+ {
+ buffer_free (&cache);
+ return -1;
+ }
+
+ 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 },
@@ -1418,6 +1560,42 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
return (unsigned long long) crc;
}
+/* Handle the "qbtrace" packet. */
+
+static int
+handle_btrace_query (char *own_buf)
+{
+ if (strncmp ("qbtrace", own_buf, strlen ("qbtrace")) == 0)
+ {
+ struct thread_info *thread;
+
+ 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 (thread->btrace == NULL)
+ {
+ strcpy (own_buf, "E.Btrace not enabled.");
+ return -1;
+ }
+
+ strcpy (own_buf,
+ (target_btrace_has_changed (thread->btrace) ? "yes" : "no"));
+ return 1;
+ }
+ return 0;
+}
+
/* Handle all of the extended 'q' packets. */
void
@@ -1647,6 +1825,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;
}
@@ -1837,6 +2022,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 cc9a910..a597911 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;
@@ -520,6 +538,21 @@ int kill_inferior (int);
(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