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 v9 01/23] thread, btrace: add generic branch trace support


Add branch trace information to struct thread_info to hold the branch trace
information for that thread.

Add functions to enable, disable, clear, and fetch a thread's branch trace.

2013-03-04  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 btrace_disable.
	* infcmd.c: Include btrace.h.
	(detach_command): Call btrace_disconnect.
	* common/btrace-common.h: New file.


---
 gdb/Makefile.in            |    4 +-
 gdb/btrace.c               |  467 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/btrace.h               |  135 +++++++++++++
 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, 779 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 ed30db5..1cf8134 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -759,7 +759,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
 
@@ -928,7 +928,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..b6cd1c8
--- /dev/null
+++ b/gdb/btrace.c
@@ -0,0 +1,467 @@
+/* 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 "exceptions.h"
+#include "inferior.h"
+#include "target.h"
+#include "record.h"
+#include "symtab.h"
+#include "disasm.h"
+#include "source.h"
+#include "filenames.h"
+
+/* Print a record debug message.  Use do ... while (0) to avoid ambiguities
+   when used in if statements.  */
+
+#define DEBUG(msg, args...)						\
+  do									\
+    {									\
+      if (record_debug != 0)						\
+        fprintf_unfiltered (gdb_stdlog,					\
+			    "[btrace] " msg "\n", ##args);		\
+    }									\
+  while (0)
+
+#define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args)
+
+/* Initialize the instruction iterator.  */
+
+static void
+btrace_init_insn_iterator (struct btrace_thread_info *btinfo)
+{
+  DEBUG ("init insn iterator");
+
+  btinfo->insn_iterator.begin = 1;
+  btinfo->insn_iterator.end = 0;
+}
+
+/* Initialize the function iterator.  */
+
+static void
+btrace_init_func_iterator (struct btrace_thread_info *btinfo)
+{
+  DEBUG ("init func iterator");
+
+  btinfo->func_iterator.begin = 1;
+  btinfo->func_iterator.end = 0;
+}
+
+/* Compute the instruction trace from the block trace.  */
+
+static VEC (btrace_inst_s) *
+compute_itrace (VEC (btrace_block_s) *btrace)
+{
+  VEC (btrace_inst_s) *itrace;
+  struct gdbarch *gdbarch;
+  unsigned int b;
+
+  DEBUG ("compute itrace");
+
+  itrace = NULL;
+  gdbarch = target_gdbarch ();
+  b = VEC_length (btrace_block_s, btrace);
+
+  while (b-- != 0)
+    {
+      btrace_block_s *block;
+      CORE_ADDR pc;
+
+      block = VEC_index (btrace_block_s, btrace, b);
+      pc = block->begin;
+
+      /* Add instructions for this block.  */
+      for (;;)
+	{
+	  btrace_inst_s *inst;
+	  int size;
+
+	  /* We should hit the end of the block.  Warn if we went too far.  */
+	  if (block->end < pc)
+	    {
+	      warning (_("Recorded trace may be corrupted."));
+	      break;
+	    }
+
+	  inst = VEC_safe_push (btrace_inst_s, itrace, NULL);
+	  inst->pc = pc;
+
+	  /* We're done once we pushed the instruction at the end.  */
+	  if (block->end == pc)
+	    break;
+
+	  size = gdb_insn_length (gdbarch, pc);
+
+	  /* Make sure we terminate if we fail to compute the size.  */
+	  if (size <= 0)
+	    {
+	      warning (_("Recorded trace may be incomplete."));
+	      break;
+	    }
+
+	  pc += size;
+	}
+    }
+
+  return itrace;
+}
+
+/* Return the function name of a recorded function segment for printing.
+   This function never returns NULL.  */
+
+static const char *
+ftrace_print_function_name (struct btrace_func *bfun)
+{
+  struct minimal_symbol *msym;
+  struct symbol *sym;
+
+  msym = bfun->msym;
+  sym = bfun->sym;
+
+  if (sym != NULL)
+    return SYMBOL_PRINT_NAME (sym);
+
+  if (msym != NULL)
+    return SYMBOL_PRINT_NAME (msym);
+
+  return "<unknown>";
+}
+
+/* Return the file name of a recorded function segment for printing.
+   This function never returns NULL.  */
+
+static const char *
+ftrace_print_filename (struct btrace_func *bfun)
+{
+  struct minimal_symbol *msym;
+  struct symbol *sym;
+  const char *filename;
+
+  msym = bfun->msym;
+  sym = bfun->sym;
+
+  if (sym != NULL)
+    filename = symtab_to_filename_for_display (sym->symtab);
+  else if (msym != NULL)
+    {
+      filename = msym->filename;
+      if (filename == NULL || *filename == 0)
+	filename = "<unknown>";
+    }
+  else
+    filename = "<unknown>";
+
+  return filename;
+}
+
+/* Print an ftrace debug status message.  */
+
+static void
+ftrace_debug (struct btrace_func *bfun, const char *prefix)
+{
+  DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]",
+		prefix, ftrace_print_function_name (bfun),
+		ftrace_print_filename (bfun), bfun->lbegin, bfun->lend,
+		bfun->ibegin, bfun->iend);
+}
+
+/* Initialize a recorded function segment.  */
+
+static void
+ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun,
+		  struct symbol *fun, unsigned int idx)
+{
+  bfun->msym = mfun;
+  bfun->sym = fun;
+  bfun->lbegin = INT_MAX;
+  bfun->lend = 0;
+  bfun->ibegin = idx;
+  bfun->iend = idx;
+}
+
+/* Check whether the function has changed.  */
+
+static int
+ftrace_function_switched (struct btrace_func *bfun,
+			  struct minimal_symbol *mfun, struct symbol *fun)
+{
+  struct minimal_symbol *msym;
+  struct symbol *sym;
+
+  /* The function changed if we did not have one before.  */
+  if (bfun == NULL)
+    return 1;
+
+  msym = bfun->msym;
+  sym = bfun->sym;
+
+  /* If the minimal symbol changed, we certainly switched functions.  */
+  if (mfun != NULL && msym != NULL)
+    {
+      const char *bfname, *fname;
+
+      /* Check the function name.  */
+      if (strcmp_iw (SYMBOL_PRINT_NAME (mfun),
+		     SYMBOL_PRINT_NAME (msym)) != 0)
+	return 1;
+
+      /* Check the location of those functions, as well.  */
+      bfname = msym->filename;
+      fname = mfun->filename;
+      if (fname != NULL && bfname != NULL
+	  && filename_cmp (fname, bfname) != 0)
+	return 1;
+    }
+
+  /* If the symbol changed, we certainly switched functions.  */
+  if (fun != NULL && sym != NULL)
+    {
+      const char *bfname, *fname;
+
+      /* Check the function name.  */
+      if (strcmp_iw (SYMBOL_PRINT_NAME (fun),
+		     SYMBOL_PRINT_NAME (sym)) != 0)
+	return 1;
+
+      /* Check the location of those functions, as well.  */
+      bfname = symtab_to_fullname (sym->symtab);
+      fname = symtab_to_fullname (fun->symtab);
+      if (filename_cmp (fname, bfname) != 0)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Check if we should skip this file when generating the function call
+   history.  We would want to do that if, say, a macro that is defined
+   in another file is expanded in this function.  */
+
+static int
+ftrace_skip_file (struct btrace_func *bfun, const char *filename)
+{
+  struct minimal_symbol *msym;
+  struct symbol *sym;
+  const char *bfile;
+
+  msym = bfun->msym;
+  sym = bfun->sym;
+
+  if (sym != NULL)
+    bfile = symtab_to_fullname (sym->symtab);
+  else if (msym != NULL && msym->filename != NULL)
+    bfile = msym->filename;
+  else
+    bfile = "";
+
+  if (filename == NULL)
+    filename = "";
+
+  return (filename_cmp (bfile, filename) != 0);
+}
+
+/* Compute the function trace from the instruction trace.  */
+
+static VEC (btrace_func_s) *
+compute_ftrace (VEC (btrace_inst_s) *itrace)
+{
+  VEC (btrace_func_s) *ftrace;
+  struct btrace_inst *binst;
+  struct btrace_func *bfun;
+  unsigned int idx;
+
+  DEBUG ("compute ftrace");
+
+  ftrace = NULL;
+  bfun = NULL;
+
+  for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx)
+    {
+      struct symtab_and_line sal;
+      struct minimal_symbol *mfun;
+      struct symbol *fun;
+      const char *filename;
+      CORE_ADDR pc;
+
+      pc = binst->pc;
+
+      /* Try to determine the function we're in.  We use both types of symbols
+	 to avoid surprises when we sometimes get a full symbol and sometimes
+	 only a minimal symbol.  */
+      fun = find_pc_function (pc);
+      mfun = lookup_minimal_symbol_by_pc (pc);
+
+      if (fun == NULL && mfun == NULL)
+	{
+	  DEBUG_FTRACE ("no symbol at %u, pc=%s", idx,
+			core_addr_to_string_nz (pc));
+	  continue;
+	}
+
+      /* If we're switching functions, we start over.  */
+      if (ftrace_function_switched (bfun, mfun, fun))
+	{
+	  bfun = VEC_safe_push (btrace_func_s, ftrace, NULL);
+
+	  ftrace_init_func (bfun, mfun, fun, idx);
+	  ftrace_debug (bfun, "init");
+	}
+
+      /* Update the instruction range.  */
+      bfun->iend = idx;
+      ftrace_debug (bfun, "update insns");
+
+      /* Let's see if we have source correlation, as well.  */
+      sal = find_pc_line (pc, 0);
+      if (sal.symtab == NULL || sal.line == 0)
+	{
+	  DEBUG_FTRACE ("no lines at %u, pc=%s", idx,
+			core_addr_to_string_nz (pc));
+	  continue;
+	}
+
+      /* Check if we switched files.  This could happen if, say, a macro that
+	 is defined in another file is expanded here.  */
+      filename = symtab_to_fullname (sal.symtab);
+      if (ftrace_skip_file (bfun, filename))
+	{
+	  DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx,
+			core_addr_to_string_nz (pc), filename);
+	  continue;
+	}
+
+      /* Update the line range.  */
+      bfun->lbegin = min (bfun->lbegin, sal.line);
+      bfun->lend = max (bfun->lend, sal.line);
+      ftrace_debug (bfun, "update lines");
+    }
+
+  return ftrace;
+}
+
+/* See btrace.h.  */
+
+void
+btrace_enable (struct thread_info *tp)
+{
+  if (tp->btrace.target != NULL)
+    return;
+
+  if (!target_supports_btrace ())
+    error (_("Target does not support branch tracing."));
+
+  DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+  tp->btrace.target = target_enable_btrace (tp->ptid);
+}
+
+/* See btrace.h.  */
+
+void
+btrace_disable (struct thread_info *tp)
+{
+  struct btrace_thread_info *btp = &tp->btrace;
+  int errcode = 0;
+
+  if (btp->target == NULL)
+    return;
+
+  DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+  target_disable_btrace (btp->target);
+  btp->target = NULL;
+
+  btrace_clear (tp);
+}
+
+/* See btrace.h.  */
+
+void
+btrace_disconnect (void)
+{
+  struct thread_info *tp;
+
+  DEBUG ("disconnect");
+
+  ALL_THREADS (tp)
+    btrace_disable (tp);
+}
+
+/* See btrace.h.  */
+
+void
+btrace_fetch (struct thread_info *tp)
+{
+  struct btrace_thread_info *btinfo;
+
+  DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+  btinfo = &tp->btrace;
+  if (btinfo->target == NULL)
+    return;
+
+  if (!target_btrace_has_changed (btinfo->target))
+    return;
+
+  btrace_clear (tp);
+
+  btinfo->btrace = target_read_btrace (btinfo->target);
+  btinfo->itrace = compute_itrace (btinfo->btrace);
+  btinfo->ftrace = compute_ftrace (btinfo->itrace);
+
+  /* Initialize branch trace iterators.  */
+  btrace_init_insn_iterator (btinfo);
+  btrace_init_func_iterator (btinfo);
+}
+
+/* See btrace.h.  */
+
+void
+btrace_clear (struct thread_info *tp)
+{
+  struct btrace_thread_info *btinfo;
+
+  DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
+
+  btinfo = &tp->btrace;
+
+  VEC_free (btrace_block_s, btinfo->btrace);
+  VEC_free (btrace_inst_s, btinfo->itrace);
+  VEC_free (btrace_func_s, btinfo->ftrace);
+
+  btinfo->btrace = NULL;
+  btinfo->itrace = NULL;
+  btinfo->ftrace = NULL;
+}
+
+/* See btrace.h.  */
+
+void
+btrace_free_objfile (struct objfile *objfile)
+{
+  struct thread_info *tp;
+
+  DEBUG ("free objfile");
+
+  ALL_THREADS (tp)
+    btrace_clear (tp);
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
new file mode 100644
index 0000000..a1b01c8
--- /dev/null
+++ b/gdb/btrace.h
@@ -0,0 +1,135 @@
+/* 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;
+
+/* A branch trace instruction.
+
+   This represents a single instruction in a branch trace.  */
+struct btrace_inst
+{
+  /* The address of this instruction.  */
+  CORE_ADDR pc;
+};
+
+/* A branch trace function.
+
+   This represents a function segment in a branch trace, i.e. a consecutive
+   number of instructions belonging to the same function.  */
+struct btrace_func
+{
+  /* The full and minimal symbol for the function.  One of them may be NULL.  */
+  struct minimal_symbol *msym;
+  struct symbol *sym;
+
+  /* The source line range of this function segment (both inclusive).  */
+  int lbegin, lend;
+
+  /* The instruction number range in the instruction trace corresponding
+     to this function segment.  */
+  unsigned int ibegin, iend;
+};
+
+/* Branch trace may also be represented as a vector of:
+
+   - branch trace instructions starting with the oldest instruction.
+   - branch trace functions starting with the oldest function.  */
+typedef struct btrace_inst btrace_inst_s;
+typedef struct btrace_func btrace_func_s;
+
+/* Define functions operating on branch trace vectors.  */
+DEF_VEC_O (btrace_inst_s);
+DEF_VEC_O (btrace_func_s);
+
+/* Branch trace iteration state for "record instruction-history".  */
+struct btrace_insn_iterator
+{
+  /* The instruction index range [begin; end[ that has been covered last time.
+     If end < begin, the branch trace has just been updated.  */
+  unsigned int begin;
+  unsigned int end;
+};
+
+/* Branch trace iteration state for "record function-call-history".  */
+struct btrace_func_iterator
+{
+  /* The function index range [begin; end[ that has been covered last time.
+     If end < begin, the branch trace has just been updated.  */
+  unsigned int begin;
+  unsigned int end;
+};
+
+/* 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;
+  VEC (btrace_inst_s) *itrace;
+  VEC (btrace_func_s) *ftrace;
+
+  /* The instruction history iterator.  */
+  struct btrace_insn_iterator insn_iterator;
+
+  /* The function call history iterator.  */
+  struct btrace_func_iterator func_iterator;
+};
+
+/* Enable branch tracing for a thread.  */
+extern void btrace_enable (struct thread_info *tp);
+
+/* Disable branch tracing for a thread.
+   This will also delete the current branch trace data.  */
+extern void btrace_disable (struct thread_info *);
+
+/* Disconnect branch tracing on detach.  */
+extern void btrace_disconnect (void);
+
+/* Fetch the branch trace for a single thread.  */
+extern void btrace_fetch (struct thread_info *);
+
+/* Clear the branch trace for a single thread.  */
+extern void btrace_clear (struct thread_info *);
+
+/* Clear the branch trace for all threads when an object file goes away.  */
+extern void btrace_free_objfile (struct objfile *);
+
+#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 824e4d0..0846322 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -27,6 +27,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),...  */
@@ -226,6 +227,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 1ef3b48..d808e92 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"
 
 /* Local functions: */
 
@@ -2725,6 +2726,7 @@ detach_command (char *args, int from_tty)
     error (_("The program is not being run."));
 
   disconnect_tracing (from_tty);
+  btrace_disconnect ();
 
   target_detach (args, from_tty);
 
diff --git a/gdb/target.c b/gdb/target.c
index ecb1325..9dfbe08 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4147,6 +4147,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 1971265..628c108 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 6b53c7a..cffaa42 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -33,6 +33,7 @@
 #include "regcache.h"
 #include "gdb.h"
 #include "gdb_string.h"
+#include "btrace.h"
 
 #include <ctype.h>
 #include <sys/types.h>
@@ -116,6 +117,8 @@ clear_thread_inferior_resources (struct thread_info *tp)
 
   bpstat_clear (&tp->control.stop_bpstat);
 
+  btrace_disable (tp);
+
   do_all_intermediate_continuations_thread (tp, 1);
   do_all_continuations_thread (tp, 1);
 }
-- 
1.7.1


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