This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch v5 01/12] thread, btrace: add generic branch trace support
- From: markus dot t dot metzger at intel dot com
- To: gdb-patches at sourceware dot org
- Cc: markus dot t dot metzger at gmail dot com, jan dot kratochvil at redhat dot com, palves at redhat dot com, tromey at redhat dot com, kettenis at gnu dot org, Markus Metzger <markus dot t dot metzger at intel dot com>
- Date: Fri, 7 Dec 2012 11:37:13 +0100
- Subject: [patch v5 01/12] thread, btrace: add generic branch trace support
- References: <1354876644-25749-1-git-send-email-markus.t.metzger@intel.com>
From: Markus Metzger <markus.t.metzger@intel.com>
Add branch trace information to struct thread_info to hold the branch trace
information for that thread.
Add functions to enable/disable, and get a thread's branch trace, as well as
for iterating over it.
Iteration uses a per-thread iterator stored in the thread_info's branch trace
information.
Iterators are reset implicitly when a thread's branch trace changes.
2012-12-07 Markus Metzger <markus.t.metzger@intel.com>
* target.h: Include btrace.h.
(struct target_ops): Add btrace ops.
* target.c (update_current_target): Initialize btrace ops.
(target_supports_btrace): New function.
(target_enable_btrace): New function.
(target_disable_btrace): New function.
(target_read_btrace): New function.
(target_btrace_has_changed): New function.
* btrace.h: New file.
* btrace.c: New file.
* Makefile.in: Add btrace.c.
* gdbthread.h: Include btrace.h.
(struct thread_info): Add btrace field.
* thread.c: Include btrace.h.
(free_thread): Call disable_btrace.
* infcmd.c: Include btrace.h.
(detach_command): Call disconnect_btrace.
* common/btrace-common.h: New file.
---
gdb/Makefile.in | 4 +-
gdb/btrace.c | 168 ++++++++++++++++++++++++++++++++++++++++++++
gdb/btrace.h | 83 ++++++++++++++++++++++
gdb/common/btrace-common.h | 62 ++++++++++++++++
gdb/gdbthread.h | 4 +
gdb/infcmd.c | 2 +
gdb/target.c | 69 ++++++++++++++++++
gdb/target.h | 35 +++++++++
gdb/thread.c | 4 +
9 files changed, 429 insertions(+), 2 deletions(-)
create mode 100644 gdb/btrace.c
create mode 100644 gdb/btrace.h
create mode 100644 gdb/common/btrace-common.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9f6f3a9..ac34f9f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -751,7 +751,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
regset.c sol-thread.c windows-termcap.c \
common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
- common/format.c
+ common/format.c btrace.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -917,7 +917,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
- format.o registry.o
+ format.o registry.o btrace.o
TSOBS = inflow.o
diff --git a/gdb/btrace.c b/gdb/btrace.c
new file mode 100644
index 0000000..418f360
--- /dev/null
+++ b/gdb/btrace.c
@@ -0,0 +1,168 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "btrace.h"
+#include "gdbthread.h"
+#include "regcache.h"
+#include "exceptions.h"
+#include "inferior.h"
+#include "target.h"
+
+/* See btrace.h. */
+
+void
+enable_btrace (struct thread_info *tp)
+{
+ if (tp->btrace.target)
+ return;
+
+ if (!target_supports_btrace ())
+ error (_("Target does not support branch tracing."));
+
+ tp->btrace.target = target_enable_btrace (tp->ptid);
+}
+
+/* See btrace.h. */
+
+void
+disable_btrace (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+ int errcode = 0;
+
+ if (!btp->target)
+ return;
+
+ if (!target_supports_btrace ())
+ return;
+
+ target_disable_btrace (btp->target);
+ btp->target = NULL;
+
+ VEC_free (btrace_block_s, btp->btrace);
+}
+
+/* See btrace.h. */
+
+void
+disconnect_btrace (void)
+{
+ struct thread_info *tp;
+
+ ALL_THREADS (tp)
+ disable_btrace (tp);
+}
+
+/* Update the thread's branch trace data in case of new trace. */
+
+static void
+update_btrace (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+
+ if (btp->target && target_btrace_has_changed (btp->target))
+ {
+ btp->btrace = target_read_btrace (btp->target);
+ btp->iterator = -1;
+
+ /* The first block ends at the current pc. */
+ if (!VEC_empty (btrace_block_s, btp->btrace))
+ {
+ struct regcache *regcache;
+ struct btrace_block *head;
+
+ regcache = get_thread_regcache (tp->ptid);
+ head = VEC_index (btrace_block_s, btp->btrace, 0);
+ if (head && !head->end)
+ head->end = regcache_read_pc (regcache);
+ }
+ }
+}
+
+/* See btrace.h. */
+
+VEC (btrace_block_s) *
+get_btrace (struct thread_info *tp)
+{
+ update_btrace (tp);
+
+ return tp->btrace.btrace;
+}
+
+/* See btrace.h. */
+
+struct btrace_block *
+read_btrace (struct thread_info *tp, int index)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+
+ if (index < 0)
+ error (_("Invalid index: %d."), index);
+
+ update_btrace (tp);
+ btp->iterator = index;
+
+ if (btp->iterator >= VEC_length (btrace_block_s, btp->btrace))
+ {
+ btp->iterator = VEC_length (btrace_block_s, btp->btrace);
+ return NULL;
+ }
+
+ return VEC_index (btrace_block_s, btp->btrace, btp->iterator);
+}
+
+/* See btrace.h. */
+
+struct btrace_block *
+prev_btrace (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+
+ update_btrace (tp);
+ btp->iterator += 1;
+
+ if (btp->iterator >= VEC_length (btrace_block_s, btp->btrace))
+ {
+ btp->iterator = VEC_length (btrace_block_s, btp->btrace);
+ return NULL;
+ }
+
+ return VEC_index (btrace_block_s, btp->btrace, btp->iterator);
+}
+
+/* See btrace.h. */
+
+struct btrace_block *
+next_btrace (struct thread_info *tp)
+{
+ struct btrace_thread_info *btp = &tp->btrace;
+
+ update_btrace (tp);
+ btp->iterator -= 1;
+
+ if (btp->iterator <= -1)
+ {
+ btp->iterator = -1;
+ return NULL;
+ }
+
+ return VEC_index (btrace_block_s, btp->btrace, btp->iterator);
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
new file mode 100644
index 0000000..df9df23
--- /dev/null
+++ b/gdb/btrace.h
@@ -0,0 +1,83 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef BTRACE_H
+#define BTRACE_H
+
+/* Branch tracing (btrace) is a per-thread control-flow execution trace of the
+ inferior. For presentation purposes, the branch trace is represented as a
+ list of sequential control-flow blocks, one such list per thread. */
+
+#include "btrace-common.h"
+
+struct thread_info;
+
+/* Branch trace information per thread.
+
+ This represents the branch trace configuration as well as the entry point
+ into the branch trace data. For the latter, it also contains the index into
+ an array of branch trace blocks used for iterating though the branch trace
+ blocks of a thread. */
+struct btrace_thread_info
+{
+ /* The target branch trace information for this thread.
+
+ This contains the branch trace configuration as well as any
+ target-specific information necessary for implementing branch tracing on
+ the underlying architecture. */
+ struct btrace_target_info *target;
+
+ /* The current branch trace for this thread. */
+ VEC (btrace_block_s) *btrace;
+
+ /* The current iterator position in the above trace vector.
+ In additon to valid vector indices, the iterator can be:
+
+ -1 one before the head
+ VEC_length() one after the tail */
+ int iterator;
+};
+
+/* Enable branch tracing for a thread. */
+extern void enable_btrace (struct thread_info *tp);
+
+/* Disable branch tracing for a thread.
+ This will also delete the current branch trace data. */
+extern void disable_btrace (struct thread_info *);
+
+/* Disconnect branch tracing on detach. */
+extern void disconnect_btrace (void);
+
+/* Return the current branch trace vector for a thread, or NULL if there is no
+ branch trace data available. */
+extern VEC (btrace_block_s) *get_btrace (struct thread_info *);
+
+/* Functions to iterate over a thread's branch trace.
+ There is one global iterator per thread. The iterator is reset implicitly
+ when branch trace for this thread changes.
+ On success, read_btrace sets the iterator to the returned trace entry.
+ Returns the selected block or NULL if there is no trace or the iterator is
+ out of bounds. */
+extern struct btrace_block *read_btrace (struct thread_info *, int);
+extern struct btrace_block *prev_btrace (struct thread_info *);
+extern struct btrace_block *next_btrace (struct thread_info *);
+
+#endif /* BTRACE_H */
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
new file mode 100644
index 0000000..90372ba
--- /dev/null
+++ b/gdb/common/btrace-common.h
@@ -0,0 +1,62 @@
+/* Branch trace support for GDB, the GNU debugger.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ Contributed by Intel Corp. <markus.t.metzger@intel.com>.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef BTRACE_COMMON_H
+#define BTRACE_COMMON_H
+
+/* Branch tracing (btrace) is a per-thread control-flow execution trace of the
+ inferior. For presentation purposes, the branch trace is represented as a
+ list of sequential control-flow blocks, one such list per thread. */
+
+#ifdef GDBSERVER
+# include "server.h"
+#else
+# include "defs.h"
+#endif
+
+#include "vec.h"
+
+/* A branch trace block.
+
+ This represents a block of sequential control-flow. Adjacent blocks will be
+ connected via calls, returns, or jumps. The latter can be direct or
+ indirect, conditional or unconditional. Branches can further be
+ asynchronous, e.g. interrupts. */
+struct btrace_block
+{
+ /* The address of the first instruction in the block. */
+ CORE_ADDR begin;
+
+ /* The address of the last instruction in the block. */
+ CORE_ADDR end;
+};
+
+/* Branch trace is represented as a vector of branch trace blocks starting with
+ the most recent block. */
+typedef struct btrace_block btrace_block_s;
+
+/* Define functions operating on a vector of branch trace blocks. */
+DEF_VEC_O (btrace_block_s);
+
+/* Target specific branch trace information. */
+struct btrace_target_info;
+
+#endif /* BTRACE_COMMON_H */
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 0250555..69320f3 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -28,6 +28,7 @@ struct symtab;
#include "frame.h"
#include "ui-out.h"
#include "inferior.h"
+#include "btrace.h"
/* Frontend view of the thread state. Possible extensions: stepping,
finishing, until(ling),... */
@@ -227,6 +228,9 @@ struct thread_info
/* Function that is called to free PRIVATE. If this is NULL, then
xfree will be called on PRIVATE. */
void (*private_dtor) (struct private_thread_info *);
+
+ /* Branch trace information for this thread. */
+ struct btrace_thread_info btrace;
};
/* Create an empty thread list, or empty the existing one. */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index db9b9b5..cc8bedb 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -56,6 +56,7 @@
#include "inf-loop.h"
#include "continuations.h"
#include "linespec.h"
+#include "btrace.h"
/* Functions exported for general use, in inferior.h: */
@@ -2745,6 +2746,7 @@ detach_command (char *args, int from_tty)
error (_("The program is not being run."));
disconnect_tracing (from_tty);
+ disconnect_btrace ();
target_detach (args, from_tty);
diff --git a/gdb/target.c b/gdb/target.c
index 5015e51..90f3a4b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4149,6 +4149,75 @@ target_ranged_break_num_registers (void)
return -1;
}
+/* See target.h. */
+int
+target_supports_btrace (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_supports_btrace != NULL)
+ return t->to_supports_btrace ();
+
+ return 0;
+}
+
+/* See target.h. */
+struct btrace_target_info *
+target_enable_btrace (ptid_t ptid)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_enable_btrace != NULL)
+ return t->to_enable_btrace (ptid);
+
+ tcomplain ();
+ return NULL;
+}
+
+/* See target.h. */
+void
+target_disable_btrace (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_disable_btrace != NULL)
+ return t->to_disable_btrace (btinfo);
+
+ tcomplain ();
+}
+
+/* See target.h. */
+int
+target_btrace_has_changed (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_btrace_has_changed != NULL)
+ return t->to_btrace_has_changed (btinfo);
+
+ tcomplain ();
+ return 0;
+}
+
+/* See target.h. */
+VEC (btrace_block_s) *
+target_read_btrace (struct btrace_target_info *btinfo)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_read_btrace != NULL)
+ return t->to_read_btrace (btinfo);
+
+ tcomplain ();
+ return NULL;
+}
+
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
diff --git a/gdb/target.h b/gdb/target.h
index 7907ee1..4889ce4 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -62,6 +62,7 @@ struct expression;
#include "memattr.h"
#include "vec.h"
#include "gdb_signals.h"
+#include "btrace.h"
enum strata
{
@@ -857,6 +858,22 @@ struct target_ops
/* Is the target able to use agent in current state? */
int (*to_can_use_agent) (void);
+ /* Check whether the target supports branch tracing. */
+ int (*to_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 *(*to_enable_btrace) (ptid_t ptid);
+
+ /* Disable branch tracing and deallocate @tinfo. */
+ void (*to_disable_btrace) (struct btrace_target_info *tinfo);
+
+ /* Check whether branch trace changed on the target. */
+ int (*to_btrace_has_changed) (struct btrace_target_info *);
+
+ /* Read branch trace data. */
+ VEC (btrace_block_s) *(*to_read_btrace) (struct btrace_target_info *);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1894,4 +1911,22 @@ extern void update_target_permissions (void);
/* Blank target vector entries are initialized to target_ignore. */
void target_ignore (void);
+/* Check whether the target supports branch tracing. */
+extern int target_supports_btrace (void);
+
+/* Enable branch tracing for @ptid.
+ Returns a branch tracing target info object. */
+extern struct btrace_target_info *target_enable_btrace (ptid_t ptid);
+
+/* Disable branch tracing. Deallocates @btinfo. */
+extern void target_disable_btrace (struct btrace_target_info *btinfo);
+
+/* Check whether there is no branch tracing data available. */
+extern int target_btrace_has_changed (struct btrace_target_info *btinfo);
+
+/* Read branch tracing data.
+ Returns a vector of branch trace blocks with the latest entry at index 0. */
+extern VEC (btrace_block_s) *target_read_btrace (struct btrace_target_info *);
+
+
#endif /* !defined (TARGET_H) */
diff --git a/gdb/thread.c b/gdb/thread.c
index 7e8eec5..e6b8c6a 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -34,6 +34,7 @@
#include "regcache.h"
#include "gdb.h"
#include "gdb_string.h"
+#include "btrace.h"
#include <ctype.h>
#include <sys/types.h>
@@ -132,6 +133,9 @@ free_thread (struct thread_info *tp)
xfree (tp->private);
}
+ if (tp->btrace.target)
+ disable_btrace (tp);
+
xfree (tp->name);
xfree (tp);
}
--
1.7.1