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 3/5] Read CTF by the ctf target


This patch adds a new target 'ctf' in GDB, so GDB can read CTF trace
data in this target.  Some of the implementations of target vector for
ctf target are copied from tfile target, so some of them can be shared
in the future.

We use libbabeltrace to read CTF data, because libbabeltrace is
designed to do this, and we don't have to reinvent the wheel again in
GDB.  Some configure stuff is modified to check whether the
libbabeltrace is installed.

gdb:

2013-02-27  Hui Zhu  <hui_zhu@mentor.com>
	    Yao Qi  <yao@codesourcery.com>

	* configure.ac: Check libbabeltrace is installed.
	* config.in: Regenerate.
	* configure: Regenerate.
	* Makefile.in (LIBBABELTRACE, LIBBABELTRACE_CFLAGS): New.
	(INTERNAL_CFLAGS_BASE): Append LIBBABELTRACE_CFLAGS.
	(CLIBS): Add LIBBABELTRACE.
	* ctf.c (ctx, ctf_iter, trace_dirname): New.
	(ctf_close_dir, ctf_open_dir, ctf_open): New.
	(ctf_close, ctf_files_info): New.
	(ctf_fetch_registers, ctf_xfer_partial): New.
	(ctf_get_trace_state_variable_value): New.
	(ctf_get_tpnum_from_frame_event): New.
	(ctf_get_traceframe_address): New.
	(ctf_trace_find, ctf_has_all_memory): New.
	(ctf_has_memory, ctf_has_stack): New.
	(ctf_has_registers, ctf_thread_alive): New.
	(ctf_traceframe_info, init_ctf_ops): New.
	(_initialize_ctf): New.

	* tracepoint.c (traceframe_number, tracepoint_number): Remove
	'static'.
	(struct traceframe_info): Move it to ...
	* tracepoint.h: ... here.
	(tracepoint_number, tracepoint_number): Declare.
---
 gdb/Makefile.in  |   10 +-
 gdb/config.in    |    3 +
 gdb/configure    |   92 +++++++
 gdb/configure.ac |   50 ++++
 gdb/ctf.c        |  733 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/tracepoint.c |   12 +-
 gdb/tracepoint.h |   12 +
 7 files changed, 900 insertions(+), 12 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5be6c77..df5404a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,11 @@ LIBEXPAT = @LIBEXPAT@
 # Where is lzma?  This will be empty if lzma was not available.
 LIBLZMA = @LIBLZMA@
 
+# Where is libbabeltrace? This will be empty if lzma was not available.
+LIBBABELTRACE = @btlibs@
+LIBBABELTRACE_CFLAGS = @btinc@
+
+
 WARN_CFLAGS = @WARN_CFLAGS@
 WERROR_CFLAGS = @WERROR_CFLAGS@
 GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -453,7 +458,8 @@ INTERNAL_CFLAGS_BASE = \
 	$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
 	$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
 	$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
-	$(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+	$(INTL_CFLAGS) $(INCGNU) $(LIBBABELTRACE_CFLAGS) \
+	$(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
 INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
 INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
 
@@ -475,7 +481,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
 # LIBIBERTY appears twice on purpose.
 CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
-	$(LIBEXPAT) $(LIBLZMA) \
+	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
 	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
 CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
 /* Define if your <locale.h> file defines LC_MESSAGES. */
 #undef HAVE_LC_MESSAGES
 
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
 /* Define to 1 if you have the `dl' library (-ldl). */
 #undef HAVE_LIBDL
 
diff --git a/gdb/configure b/gdb/configure
index c54709c..3f8c6d1 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,8 @@ enable_option_checking=no
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
 GDB_NM_FILE
+btinc
+btlibs
 frags
 target_subdir
 CONFIG_UNINSTALL
@@ -819,6 +821,9 @@ with_x
 enable_sim
 enable_multi_ice
 enable_gdbserver
+with_babeltrace
+with_bt_include
+with_bt_lib
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1532,6 +1537,11 @@ Optional Packages:
   --with-tcl              directory containing tcl configuration (tclConfig.sh)
   --with-tk               directory containing tk configuration (tkConfig.sh)
   --with-x                use the X Window System
+  --with-babeltrace=PATH       Specify prefix directory for the installed BABELTRACE package
+                          Equivalent to --with-babeltrace-include=PATH/include
+                          plus --with-babeltrace-lib=PATH/lib
+  --with-babeltrace-include=PATH Specify directory for installed babeltrace include files
+  --with-babeltrace-lib=PATH   Specify the directory for the installed babeltrace library
 
 Some influential environment variables:
   CC          C compiler command
@@ -14090,6 +14100,88 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
   as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
 fi
 
+# Check for babeltrace and babeltrace-ctf
+btlibs=""
+btinc=""
+
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+  withval=$with_babeltrace;
+fi
+
+
+# Check whether --with-bt_include was given.
+if test "${with_bt_include+set}" = set; then :
+  withval=$with_bt_include;
+fi
+
+
+# Check whether --with-bt_lib was given.
+if test "${with_bt_lib+set}" = set; then :
+  withval=$with_bt_lib;
+fi
+
+
+case $with_babeltrace in
+  no)
+    btlibs=
+    btinc=
+    ;;
+  "" | yes)
+    btlibs=" -lbabeltrace -lbabeltrace-ctf "
+    btinc=""
+    ;;
+  *)
+    btlibs="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+    btinc="-I$with_babeltrace/include "
+    ;;
+esac
+if test "x$with_bt_include" != x; then
+  btinc="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+  tlibs="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $btinc"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for babeltrace" >&5
+$as_echo_n "checking for babeltrace... " >&6; }
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; btlibs= ; btinc=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  CFLAGS="$saved_CFLAGS"
+fi
+
+# Flags needed for UST
+
+
+
+
 # If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
 # to an empty version.
 
diff --git a/gdb/configure.ac b/gdb/configure.ac
index e501766..e5bf83c 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2318,6 +2318,56 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
   AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
 fi
 
+# Check for babeltrace and babeltrace-ctf
+btlibs=""
+btinc=""
+
+AC_ARG_WITH(babeltrace, [  --with-babeltrace=PATH       Specify prefix directory for the installed BABELTRACE package
+                          Equivalent to --with-babeltrace-include=PATH/include
+                          plus --with-babeltrace-lib=PATH/lib])
+AC_ARG_WITH(bt_include, [  --with-babeltrace-include=PATH Specify directory for installed babeltrace include files])
+AC_ARG_WITH(bt_lib, [  --with-babeltrace-lib=PATH   Specify the directory for the installed babeltrace library])
+
+case $with_babeltrace in
+  no)
+    btlibs=
+    btinc=
+    ;;
+  "" | yes)
+    btlibs=" -lbabeltrace -lbabeltrace-ctf "
+    btinc=""
+    ;;
+  *)
+    btlibs="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+    btinc="-I$with_babeltrace/include "
+    ;;
+esac
+if test "x$with_bt_include" != x; then
+  btinc="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+  tlibs="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $btinc"
+  AC_MSG_CHECKING([for babeltrace])
+  AC_TRY_COMPILE([
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+  ],[],
+  [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_LIBBABELTRACE, 1, [Define if libbabeltrace is available])],
+  [AC_MSG_RESULT([no]); btlibs= ; btinc= ])
+  CFLAGS="$saved_CFLAGS"
+fi
+
+# Flags needed for UST
+AC_SUBST(btlibs)
+AC_SUBST(btinc)
+
+
 # If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
 # to an empty version.
 
diff --git a/gdb/ctf.c b/gdb/ctf.c
index c4809d8..fe28d42 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -23,6 +23,7 @@
 #include "ctf.h"
 #include "tracepoint.h"
 #include "regcache.h"
+#include "exec.h"
 
 #include <ctype.h>
 
@@ -678,3 +679,735 @@ ctf_trace_file_writer (void)
 
   return writer;
 }
+
+#ifdef HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data.  The libbabeltrace provides
+   iterator to iterate over each event in CTF data and APIs to get
+   details of event and packet, so it is very convenient to use
+   libbabeltrace to access events in CTF.  */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory.  */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory.  */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+static void
+ctf_close_dir (void)
+{
+  if (ctf_iter)
+    {
+      bt_ctf_iter_destroy (ctf_iter);
+      ctf_iter = NULL;
+    }
+  if (ctx)
+    {
+      bt_context_put (ctx);
+      ctx = NULL;
+    }
+}
+
+extern int trace_regblock_size;
+
+/* Open CTF trace data in DIRNAME.  */
+
+static void
+ctf_open_dir (char *dirname)
+{
+  int ret;
+  struct bt_iter_pos begin_pos;
+  struct bt_iter_pos *pos;
+
+  ctx = bt_context_create ();
+  if (!ctx)
+    error (_("Unable to initialize libbabeltrace"));
+  ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+  if (ret < 0)
+    {
+      ctf_close_dir ();
+      error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+    }
+
+  begin_pos.type = BT_SEEK_BEGIN;
+  ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+  if (ctf_iter == NULL)
+    {
+      ctf_close_dir ();
+      error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+    }
+
+  /* Iterate over events, and look for an event for register block
+     to set trace_regblock_size.  */
+
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (name == NULL)
+	break;
+      else if (strcmp (name, "register") == 0)
+	{
+	  const struct bt_definition *scope
+	    = bt_ctf_get_top_level_scope(event,
+					 BT_EVENT_FIELDS);
+	  const struct bt_definition *array
+	    = bt_ctf_get_field(event, scope, "contents");
+
+	  trace_regblock_size
+	    = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+}
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+  target_preopen (from_tty);
+  if (!dirname)
+    error (_("No CTF directory specified."));
+
+  ctf_open_dir (dirname);
+
+  trace_dirname = xstrdup (dirname);
+  push_target (&ctf_ops);
+}
+
+static void
+ctf_close (int quitting)
+{
+  ctf_close_dir ();
+  xfree (trace_dirname);
+  trace_dirname = NULL;
+}
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+  printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* Iterate over events whose name is "register" in current frame,
+   extract contents from events, and set REGCACHE with the contents.
+   If no matched events are found, mark registers unavailable.  */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+		     struct regcache *regcache, int regno)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset, regn, regsize, pc_regno;
+  char *regs = NULL;
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos;
+
+  /* An uninitialized reg size says we're not going to be
+     successful at getting register blocks.  */
+  if (!trace_regblock_size)
+    return;
+
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL || strcmp (name, "frame") == 0)
+	break;
+      else if (strcmp (name, "register") == 0)
+	{
+	  event = event1;
+	  break;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+  if (event != NULL)
+    {
+      const struct bt_definition *scope
+	= bt_ctf_get_top_level_scope(event,
+				     BT_EVENT_FIELDS);
+      const struct bt_definition *array
+	= bt_ctf_get_field(event, scope, "contents");
+
+      regs = bt_ctf_get_char_array (array);
+      /* Assume the block is laid out in GDB register number order,
+	 each register with the size that it has in GDB.  */
+      offset = 0;
+      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+	{
+	  regsize = register_size (gdbarch, regn);
+	  /* Make sure we stay within block bounds.  */
+	  if (offset + regsize >= trace_regblock_size)
+	    break;
+	  if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+	    {
+	      if (regno == regn)
+		{
+		  regcache_raw_supply (regcache, regno, regs + offset);
+		  break;
+		}
+	      else if (regno == -1)
+		{
+		  regcache_raw_supply (regcache, regn, regs + offset);
+		}
+	    }
+	  offset += regsize;
+	}
+      /* xfree (regs); */
+      return;
+    }
+
+  regs = alloca (trace_regblock_size);
+
+  /* We get here if no register data has been found.  Mark registers
+     as unavailable.  */
+  for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+    regcache_raw_supply (regcache, regn, NULL);
+
+  /* We can often usefully guess that the PC is going to be the same
+     as the address of the tracepoint.  */
+  pc_regno = gdbarch_pc_regnum (gdbarch);
+  if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+    {
+      struct tracepoint *tp = get_tracepoint (tracepoint_number);
+
+      if (tp && tp->base.loc)
+	{
+	  /* But don't try to guess if tracepoint is multi-location...  */
+	  if (tp->base.loc->next)
+	    {
+	      warning (_("Tracepoint %d has multiple "
+			 "locations, cannot infer $pc"),
+		       tp->base.number);
+	      return;
+	    }
+	  /* ... or does while-stepping.  */
+	  if (tp->step_count > 0)
+	    {
+	      warning (_("Tracepoint %d does while-stepping, "
+			 "cannot infer $pc"),
+		       tp->base.number);
+	      return;
+	    }
+
+	  store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+				  gdbarch_byte_order (gdbarch),
+				  tp->base.loc->address);
+	  regcache_raw_supply (regcache, pc_regno, regs);
+	}
+    }
+}
+
+/* Iterate over events whose name is started with "memory_" in
+   current frame, extract the address and length from events.  If
+   OFFSET is within the range, read the contents from events to
+   READBUF.  */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+		  const char *annex, gdb_byte *readbuf,
+		  const gdb_byte *writebuf, ULONGEST offset,
+		  LONGEST len)
+{
+  /* We're only doing regular memory for now.  */
+  if (object != TARGET_OBJECT_MEMORY)
+    return -1;
+
+  if (readbuf == NULL)
+    error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (traceframe_number != -1)
+    {
+      struct bt_iter_pos *pos;
+      int i = 0;
+
+      /* Save the current position.  */
+      pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+      gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+      /* Iterate through the traceframe's blocks, looking for
+	 memory.  */
+      while (1)
+	{
+	  ULONGEST maddr, amt;
+	  unsigned short mlen;
+	  enum bfd_endian byte_order
+	    = gdbarch_byte_order (target_gdbarch ());
+	  const struct bt_definition *scope;
+	  const struct bt_definition *def;
+	  struct bt_ctf_event *event
+	    = bt_ctf_iter_read_event (ctf_iter);
+	  const char *name = bt_ctf_event_name (event);
+
+	  if (strcmp (name, "frame") == 0)
+	    break;
+	  else if (strncmp (name, "memory_", 7) != 0)
+	    {
+	      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+		break;
+
+	      continue;
+	    }
+
+	  scope = bt_ctf_get_top_level_scope(event,
+					     BT_EVENT_FIELDS);
+
+	  def = bt_ctf_get_field (event, scope, "address");
+	  maddr = bt_ctf_get_uint64 (def);
+	  def = bt_ctf_get_field (event, scope, "length");
+	  mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+	  /* If the block includes the first part of the desired
+	     range, return as much it has; GDB will re-request the
+	     remainder, which might be in a different block of this
+	     trace frame.  */
+	  if (maddr <= offset && offset < (maddr + mlen))
+	    {
+	      const struct bt_definition *array
+		= bt_ctf_get_field(event, scope, "contents");
+	      const struct bt_declaration *decl
+		= bt_ctf_get_decl_from_def (array);
+	      gdb_byte *contents;
+
+	      gdb_assert (mlen == bt_ctf_get_array_len (decl));
+	      contents = bt_ctf_get_char_array (array);
+
+	      amt = (maddr + mlen) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      memcpy (readbuf, &contents[offset - maddr], amt);
+
+	      /* Restore the position.  */
+	      bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+	      return amt;
+	    }
+
+	  if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	    break;
+	}
+
+      /* Restore the position.  */
+      bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+    }
+
+  /* It's unduly pedantic to refuse to look at the executable for
+     read-only pieces; so do the equivalent of readonly regions aka
+     QTro packet.  */
+  /* FIXME account for relocation at some point.  */
+  if (exec_bfd)
+    {
+      asection *s;
+      bfd_size_type size;
+      bfd_vma vma;
+
+      for (s = exec_bfd->sections; s; s = s->next)
+	{
+	  if ((s->flags & SEC_LOAD) == 0
+	      || (s->flags & SEC_READONLY) == 0)
+	    continue;
+
+	  vma = s->vma;
+	  size = bfd_get_section_size (s);
+	  if (vma <= offset && offset < (vma + size))
+	    {
+	      ULONGEST amt;
+
+	      amt = (vma + size) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      amt = bfd_get_section_contents (exec_bfd, s,
+					      readbuf, offset - vma, amt);
+	      return amt;
+	    }
+	}
+    }
+
+  /* Indicate failure to find the requested memory block.  */
+  return -1;
+}
+
+/* Iterate over events whose name is "tsv" in current frame.  When the
+   trace variable is found, set the value of it to *VAL and return
+   true, otherwise return false.  */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+  struct bt_iter_pos *pos;
+  int found = 0;
+
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  /* Iterate through the traceframe's blocks, looking for 'V'
+     block.  */
+  while (1)
+    {
+      struct bt_ctf_event *event
+	= bt_ctf_iter_read_event (ctf_iter);
+      const char *name = bt_ctf_event_name (event);
+
+      if (strcmp (name, "frame") == 0)
+	break;
+      else if (strcmp (name, "tsv") == 0)
+	{
+	  const struct bt_definition *scope;
+	  const struct bt_definition *def;
+
+	  scope = bt_ctf_get_top_level_scope(event,
+					     BT_EVENT_FIELDS);
+
+	  def = bt_ctf_get_field (event, scope, "num");
+	  if (tsvnum == (int) bt_ctf_get_uint64 (def))
+	    {
+	      def = bt_ctf_get_field (event, scope, "val");
+	      *val = bt_ctf_get_uint64 (def);
+
+	      found = 1;
+	      break;
+	    }
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+  /* Didn't find anything.  */
+  return found;
+}
+
+/* Return the tracepoint number in "frame" event.  */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+  /* The packet context of events has a field "tpnum".  */
+  const struct bt_definition *scope
+    = bt_ctf_get_top_level_scope(event, BT_STREAM_PACKET_CONTEXT);
+  uint64_t tpnum
+    = bt_ctf_get_uint64 (bt_ctf_get_field(event, scope, "tpnum"));
+
+  return (int) tpnum;
+}
+
+/* Return what address the current frame was collected at.  */
+
+static ULONGEST
+ctf_get_traceframe_address (void)
+{
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos
+    = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  ULONGEST addr = 0;
+
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL)
+	break;
+      else if (strcmp (name, "frame") == 0)
+	{
+	  event = event1;
+	  break;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  if (event != NULL)
+    {
+      int tpnum = ctf_get_tpnum_from_frame_event (event);
+      struct tracepoint *tp
+	= get_tracepoint_by_number_on_target (tpnum);
+
+      /* FIXME this is a poor heuristic if multiple locations.  */
+      if (tp && tp->base.loc)
+	addr = tp->base.loc->address;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+  return addr;
+}
+
+/* Iterate the events whose name is "frame", extract the tracepoint
+   number in it.  Return traceframe number when matched.  */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+		ULONGEST addr1, ULONGEST addr2, int *tpp)
+{
+  int ret = -1;
+  int tfnum = 0;
+  int found = 0;
+  struct bt_iter_pos pos;
+
+  if (num == -1)
+    {
+      if (tpp)
+	*tpp = -1;
+      return -1;
+    }
+
+  /* Set iterator back to the beginning.  */
+  pos.type = BT_SEEK_BEGIN;
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+  while (1)
+    {
+      int id;
+      struct bt_ctf_event *event;
+      const char *name;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (event == NULL || name == NULL)
+	return -1;
+
+      if (strcmp (name, "frame") == 0)
+	{
+	  ULONGEST tfaddr;
+
+	  if (type == tfind_number)
+	    {
+	      /* Looking for a specific trace frame.  */
+	      if (tfnum == num)
+		found = 1;
+	    }
+	  else
+	    {
+	      /* Start from the _next_ trace frame.  */
+	      if (tfnum > traceframe_number)
+		{
+		  switch (type)
+		    {
+		    case tfind_tp:
+		      {
+			struct tracepoint *tp = get_tracepoint (num);
+
+			if (tp != NULL
+			    && (tp->number_on_target
+				== ctf_get_tpnum_from_frame_event (event)))
+			  found = 1;
+			break;
+		      }
+		    case tfind_pc:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (tfaddr == addr1)
+			found = 1;
+		      break;
+		    case tfind_range:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (addr1 <= tfaddr && tfaddr <= addr2)
+			found = 1;
+		      break;
+		    case tfind_outside:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (!(addr1 <= tfaddr && tfaddr <= addr2))
+			found = 1;
+		      break;
+		    default:
+		      internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+		    }
+		}
+	    }
+	  if (found)
+	    {
+	      if (tpp)
+		*tpp = ctf_get_tpnum_from_frame_event (event);
+
+	      /* Skip the event "frame".  */
+	      bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+	      return tfnum;
+	    }
+	  tfnum++;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	return -1;
+    }
+
+  return -1;
+}
+
+static int
+ctf_has_all_memory (struct target_ops *ops)
+{
+  return 0;
+}
+
+static int
+ctf_has_memory (struct target_ops *ops)
+{
+  return 0;
+}
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+  return traceframe_number != -1;
+}
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+  return traceframe_number != -1;
+}
+
+static int
+ctf_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+  return 1;
+}
+
+/* Iterate the events whose name is started with "memory_", in current
+   frame, extract memory range information, and return them in
+   traceframe_info.  */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+  struct traceframe_info *info = XCNEW (struct traceframe_info);
+  const char *name;
+  struct bt_iter_pos *pos;
+
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  do
+    {
+      struct bt_ctf_event *event
+	= bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (name == NULL || strcmp (name, "register") == 0
+	  || strcmp (name, "frame") == 0)
+	;
+      else if (strncmp (name, "memory_", 7) == 0)
+	{
+	  const struct bt_definition *scope
+	    = bt_ctf_get_top_level_scope(event,
+					 BT_EVENT_FIELDS);
+	  const struct bt_definition *def;
+	  struct mem_range *r;
+
+	  r = VEC_safe_push (mem_range_s, info->memory, NULL);
+	  def = bt_ctf_get_field (event, scope, "address");
+	  r->start = bt_ctf_get_uint64 (def);
+
+	  def = bt_ctf_get_field (event, scope, "length");
+	  r->length = (uint16_t) bt_ctf_get_uint64 (def);
+	}
+      else
+	warning (_("Unhandled trace block type (%s) "
+		   "while building trace frame info."),
+		 name);
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+  while (name != NULL && strcmp (name, "frame") != 0);
+
+  /* Restore the position.  */
+  bt_iter_set_pos(bt_ctf_get_iter (ctf_iter), pos);
+
+  /* traceframe_walk_blocks (build_traceframe_info, 0, info); */
+  return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+  ctf_ops.to_shortname = "ctf";
+  ctf_ops.to_longname = "CTF file";
+  ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+  ctf_ops.to_open = ctf_open;
+  ctf_ops.to_close = ctf_close;
+  ctf_ops.to_fetch_registers = ctf_fetch_registers;
+  ctf_ops.to_xfer_partial = ctf_xfer_partial;
+  ctf_ops.to_files_info = ctf_files_info;
+  ctf_ops.to_trace_find = ctf_trace_find;
+  ctf_ops.to_get_trace_state_variable_value
+    = ctf_get_trace_state_variable_value;
+  ctf_ops.to_stratum = process_stratum;
+  ctf_ops.to_has_all_memory = ctf_has_all_memory;
+  ctf_ops.to_has_memory = ctf_has_memory;
+  ctf_ops.to_has_stack = ctf_has_stack;
+  ctf_ops.to_has_registers = ctf_has_registers;
+  ctf_ops.to_traceframe_info = ctf_traceframe_info;
+  ctf_ops.to_thread_alive = ctf_thread_alive;
+  ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+void
+_initialize_ctf (void)
+{
+#ifdef HAVE_LIBBABELTRACE
+  init_ctf_ops ();
+
+  add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 7434df7..d214117 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -129,14 +129,6 @@ extern void (*deprecated_readline_end_hook) (void);
 typedef struct trace_state_variable tsv_s;
 DEF_VEC_O(tsv_s);
 
-/* An object describing the contents of a traceframe.  */
-
-struct traceframe_info
-{
-  /* Collected memory.  */
-  VEC(mem_range_s) *memory;
-};
-
 static VEC(tsv_s) *tvariables;
 
 /* The next integer to assign to a variable.  */
@@ -144,10 +136,10 @@ static VEC(tsv_s) *tvariables;
 static int next_tsv_number = 1;
 
 /* Number of last traceframe collected.  */
-static int traceframe_number;
+int traceframe_number;
 
 /* Tracepoint for last traceframe collected.  */
-static int tracepoint_number;
+int tracepoint_number;
 
 /* Symbol for function for last traceframe collected.  */
 static struct symbol *traceframe_fun;
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 44ff2de..008f7e2 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
 #include "memrange.h"
 #include "gdb_vecs.h"
 
+/* An object describing the contents of a traceframe.  */
+
+struct traceframe_info
+{
+  /* Collected memory.  */
+  VEC(mem_range_s) *memory;
+};
+
 /* A trace state variable is a value managed by a target being
    traced.  A trace state variable (or tsv for short) can be accessed
    and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,10 @@ struct trace_status *current_trace_status (void);
 
 extern char *default_collect;
 
+extern int tracepoint_number;
+
+extern int traceframe_number;
+
 /* Struct to collect random info about tracepoints on the target.  */
 
 struct uploaded_tp
-- 
1.7.7.6


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