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 04/17] 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-06-06 Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* target.h: Add include.
	(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: Add include.
	(struct thread_info): Add btrace field.
	* thread.c: Add include.
	(free_thread): Call disable_btrace.
	* infcmd.c: Add include.
	(detach_command): Call disconnect_btrace.


---
 gdb/Makefile.in |    4 +-
 gdb/btrace.c    |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/btrace.h    |   95 ++++++++++++++++++++++++++++++
 gdb/gdbthread.h |    4 +
 gdb/infcmd.c    |    2 +
 gdb/target.c    |   89 ++++++++++++++++++++++++++++
 gdb/target.h    |   35 +++++++++++
 gdb/thread.c    |    4 +
 8 files changed, 403 insertions(+), 2 deletions(-)
 create mode 100644 gdb/btrace.c
 create mode 100644 gdb/btrace.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bf6b0da..61ca27e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -745,7 +745,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	annotate.c common/signals.c copying.c dfp.c gdb.c inf-child.c \
 	regset.c sol-thread.c windows-termcap.c \
 	common/common-utils.c common/xml-utils.c \
-	common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c
+	common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c btrace.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -916,7 +916,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
 	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
 	jit.o progspace.o skip.o probe.o \
-	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o
+	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o btrace.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/btrace.c b/gdb/btrace.c
new file mode 100644
index 0000000..7b644f6
--- /dev/null
+++ b/gdb/btrace.c
@@ -0,0 +1,172 @@
+/* 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 "frame.h"
+#include "exceptions.h"
+#include "inferior.h"
+#include "target.h"
+
+/* Documentation see btrace.h.  */
+void
+enable_btrace (struct thread_info *tp)
+{
+  if (tp->btrace.target)
+    error (_("Branch tracing already enabled for %s."),
+	   target_pid_to_str (tp->ptid));
+
+  tp->btrace.target = target_enable_btrace (tp->ptid);
+}
+
+/* Documentation see btrace.h.  */
+void
+disable_btrace (struct thread_info *tp)
+{
+  struct btrace_thread_info *btp = &tp->btrace;
+  int errcode = 0;
+
+  if (!btp->target)
+    error (_("Branch tracing not enabled for %s."),
+	   target_pid_to_str (tp->ptid));
+
+  /* When killing the inferior, we may have lost our target before we disable
+     branch tracing.  */
+  if (target_supports_btrace ())
+    target_disable_btrace (btp->target);
+
+  btp->target = NULL;
+  VEC_free (btrace_block_s, btp->btrace);
+}
+
+/* Disable branch tracing for @tp. Ignore errors.  */
+static int
+do_disconnect_btrace (struct thread_info *tp, void *ignored)
+{
+  if (tp->btrace.target)
+    {
+      volatile struct gdb_exception error;
+
+      TRY_CATCH (error, RETURN_MASK_ERROR)
+	disable_btrace (tp);
+    }
+
+  return 0;
+}
+
+/* Documentation see btrace.h.  */
+void
+disconnect_btrace (void)
+{
+  iterate_over_threads (do_disconnect_btrace, NULL);
+}
+
+/* Update @btp's trace data in case of new trace.  */
+static void
+update_btrace (struct btrace_thread_info *btp)
+{
+  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 frame_info *frame = get_current_frame ();
+
+	  if (frame)
+	    {
+	      struct btrace_block *head =
+		VEC_index (btrace_block_s, btp->btrace, 0);
+
+	      if (head && !head->end)
+		head->end = get_frame_pc (frame);
+	    }
+	}
+    }
+}
+
+/* Documentation see btrace.h.  */
+VEC (btrace_block_s) *
+get_btrace (struct thread_info *tp)
+{
+  update_btrace (&tp->btrace);
+
+  return tp->btrace.btrace;
+}
+
+/* Documentation 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 (btp);
+  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);
+}
+
+/* Documentation see btrace.h.  */
+struct btrace_block *
+prev_btrace (struct thread_info *tp)
+{
+  struct btrace_thread_info *btp = &tp->btrace;
+
+  update_btrace (btp);
+  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);
+}
+
+/* Documentation see btrace.h.  */
+struct btrace_block *
+next_btrace (struct thread_info *tp)
+{
+  struct btrace_thread_info *btp = &tp->btrace;
+
+  update_btrace (btp);
+  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..411a84b
--- /dev/null
+++ b/gdb/btrace.h
@@ -0,0 +1,95 @@
+/* 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
+
+#include "vec.h"
+#include "defs.h"
+
+struct thread_info;
+
+/* A branch trace block.
+
+   Beware that a block is not a branch.  Rather, blocks are connected through
+   branches.  */
+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;
+DEF_VEC_O (btrace_block_s);
+
+/* Target specific branch trace information.  */
+struct btrace_target_info;
+
+/* Branch trace information per thread.  */
+struct btrace_thread_info
+{
+  /* The target branch trace information for this thread.  */
+  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
+
+     Prev and next will remain at those extreme positions.  */
+  int iterator;
+};
+
+/* Enable branch tracing for a thread.
+   Allocates the branch trace target information and stores it in @tp.  */
+extern void enable_btrace (struct thread_info *tp);
+
+/* Disable branch tracing for a thread.
+   Deallocates the branch trace target information as well as 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 ther is no
+   trace.  */
+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 iteratoris
+   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/gdbthread.h b/gdb/gdbthread.h
index 2512357..9ea4ea1 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),...  */
@@ -225,6 +226,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 5accd28..1fbcb40 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: */
 
@@ -2680,6 +2681,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 91b4b47..0ed2e65 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -701,6 +701,11 @@ update_current_target (void)
       INHERIT (to_traceframe_info, t);
       INHERIT (to_use_agent, t);
       INHERIT (to_can_use_agent, t);
+      INHERIT (to_supports_btrace, t);
+      INHERIT (to_enable_btrace, t);
+      INHERIT (to_disable_btrace, t);
+      INHERIT (to_btrace_has_changed, t);
+      INHERIT (to_read_btrace, t);
       INHERIT (to_magic, t);
       INHERIT (to_supports_evaluation_of_breakpoint_conditions, t);
       /* Do not inherit to_memory_map.  */
@@ -939,6 +944,21 @@ update_current_target (void)
 	    (int (*) (void))
 	    return_zero);
   de_fault (to_execution_direction, default_execution_direction);
+  de_fault (to_supports_btrace,
+	    (int (*) (void))
+	    return_zero);
+  de_fault (to_enable_btrace,
+	    (struct btrace_target_info * (*) (ptid_t))
+	    tcomplain);
+  de_fault (to_disable_btrace,
+      (void (*) (struct btrace_target_info *))
+	    tcomplain);
+  de_fault (to_btrace_has_changed,
+      (int (*) (struct btrace_target_info *))
+	    tcomplain);
+  de_fault (to_read_btrace,
+      (VEC (btrace_block_s) * (*) (struct btrace_target_info *))
+	    tcomplain);
 
 #undef de_fault
 
@@ -4089,6 +4109,75 @@ target_ranged_break_num_registers (void)
   return -1;
 }
 
+/* Documentation 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;
+}
+
+/* Documentation 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;
+}
+
+/* Documentation 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 ();
+}
+
+/* Documentation 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;
+}
+
+/* Documentation 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 f3ef33a..2f65e53 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
   {
@@ -849,6 +850,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?
      */
@@ -1878,4 +1895,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 d361dd8..74a9110 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


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