This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch v6 01/12] thread, btrace: add generic branch trace support


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-17 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.
	(clear_thread_inferior_resources): 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               |    3 +
 9 files changed, 428 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 244694c..d6e1dbb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -754,7 +754,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
 
@@ -921,7 +921,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..667a738
--- /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 != NULL)
+    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 == NULL)
+    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 != NULL && 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 != NULL && head->end == 0)
+	    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 4e38725..56e4403 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 ebd8085..db7a3c6 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 a832ef8..4f6f35b 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?
      */
@@ -1897,4 +1914,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..47d8a6e 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>
@@ -117,6 +118,8 @@ clear_thread_inferior_resources (struct thread_info *tp)
 
   bpstat_clear (&tp->control.stop_bpstat);
 
+  disable_btrace (tp);
+
   do_all_intermediate_continuations_thread (tp, 1);
   do_all_continuations_thread (tp, 1);
 }
-- 
1.7.6.5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]