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 v3 03/15] 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.

In V3, we fix a bug in configure.ac on checking broken libbabeltrace,
and fix some code violations like "if (foo)".

gdb:

2013-03-08  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, trace_regblock_size): Move it to ...
	* tracepoint.h: ... here.
	(tracepoint_number, tracepoint_number): Declare.
---
 gdb/Makefile.in  |   11 +-
 gdb/config.in    |    3 +
 gdb/configure    |  141 +++++++++++
 gdb/configure.ac |   82 ++++++
 gdb/ctf.c        |  741 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/tracepoint.c |   14 +-
 gdb/tracepoint.h |   14 +
 7 files changed, 992 insertions(+), 14 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5be6c77..9275b12 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,12 @@ LIBEXPAT = @LIBEXPAT@
 # Where is lzma?  This will be empty if lzma was not available.
 LIBLZMA = @LIBLZMA@
 
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+LIBBABELTRACE_CFLAGS = @LIBBABELTRACE_CFLAGS@
+
+
 WARN_CFLAGS = @WARN_CFLAGS@
 WERROR_CFLAGS = @WERROR_CFLAGS@
 GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -453,7 +459,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 +482,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..e739420 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,8 @@ enable_option_checking=no
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
 GDB_NM_FILE
+LIBBABELTRACE_CFLAGS
+LIBBABELTRACE
 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,15 @@ 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       Specify prefix directory for the installed
+                          BABELTRACE package Equivalent to
+                          --with-babeltrace-include=PATH/include plus
+                          --with-babeltrace-lib=PATH/lib
+  --with-babeltrace-include
+                          Specify directory for installed babeltrace include
+                          files
+  --with-babeltrace-lib   Specify the directory for the installed babeltrace
+                          library
 
 Some influential environment variables:
   CC          C compiler command
@@ -14090,6 +14104,133 @@ 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
+LIBBABELTRACE
+LIBBABELTRACE_CFLAGS
+
+
+# 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)
+    LIBBABELTRACE=
+    LIBBABELTRACE_CFLAGS=
+    ;;
+  "" | yes)
+    LIBBABELTRACE=" -lbabeltrace -lbabeltrace-ctf "
+    LIBBABELTRACE_CFLAGS=""
+    ;;
+  *)
+    LIBBABELTRACE="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+    LIBBABELTRACE_CFLAGS="-I$with_babeltrace/include "
+    ;;
+esac
+if test "x$with_bt_include" != x; then
+  LIBBABELTRACE_CFLAGS="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+  LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+  saved_CFLAGS=$CFLAGS
+  saved_LIBS=$LIBS
+
+  CFLAGS="$CFLAGS $LIBBABELTRACE_CFLAGS"
+  LIBS="$LIBS $LIBBABELTRACE"
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for babeltrace" >&5
+$as_echo_n "checking for babeltrace... " >&6; }
+if test "${ac_cv_has_babeltrace_header+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  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; }; ac_cv_has_babeltrace_header=yes
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; ac_cv_has_babeltrace_header=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_has_babeltrace_header" >&5
+$as_echo "$ac_cv_has_babeltrace_header" >&6; }
+
+  if test "x$ac_cv_has_babeltrace_header" != "xno"; then
+     # Check whether there is a function named 'lookup_enum' in
+     # babeltrace library.  We can't use the babeltrace library
+     # in which function 'lookup_enum' is defined.  This function
+     # is renamed to 'bt_lookup_name' in recent babeltrace.
+     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken babeltrace" >&5
+$as_echo_n "checking for broken babeltrace... " >&6; }
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+lookup_enum (NULL, NULL, 0)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; LIBBABELTRACE= ; LIBBABELTRACE_CFLAGS=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  else
+    LIBBABELTRACE=
+    LIBBABELTRACE_CFLAGS=
+  fi
+
+  CFLAGS="$saved_CFLAGS"
+  LIBS="$saved_LIBS"
+fi
+
+# Flags needed for babeltrace.
+
+
+
+
 # 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..0b784c6 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2318,6 +2318,88 @@ 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
+LIBBABELTRACE
+LIBBABELTRACE_CFLAGS
+
+AC_ARG_WITH(babeltrace,
+	    AC_HELP_STRING([--with-babeltrace],
+			   [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,
+	    AC_HELP_STRING([--with-babeltrace-include],
+			   [Specify directory for installed babeltrace include
+			    files]))
+AC_ARG_WITH(bt_lib,
+	    AC_HELP_STRING([--with-babeltrace-lib],
+			    [Specify the directory for the installed babeltrace
+			    library]))
+
+case $with_babeltrace in
+  no)
+    LIBBABELTRACE=
+    LIBBABELTRACE_CFLAGS=
+    ;;
+  "" | yes)
+    LIBBABELTRACE=" -lbabeltrace -lbabeltrace-ctf "
+    LIBBABELTRACE_CFLAGS=""
+    ;;
+  *)
+    LIBBABELTRACE="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+    LIBBABELTRACE_CFLAGS="-I$with_babeltrace/include "
+    ;;
+esac
+if test "x$with_bt_include" != x; then
+  LIBBABELTRACE_CFLAGS="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+  LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+  saved_CFLAGS=$CFLAGS
+  saved_LIBS=$LIBS
+
+  CFLAGS="$CFLAGS $LIBBABELTRACE_CFLAGS"
+  LIBS="$LIBS $LIBBABELTRACE"
+
+  AC_CACHE_CHECK([for babeltrace], ac_cv_has_babeltrace_header,
+    [AC_TRY_COMPILE([
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+  ],[],
+  [AC_MSG_RESULT([yes]); ac_cv_has_babeltrace_header=yes],
+  [AC_MSG_RESULT([no]); ac_cv_has_babeltrace_header=no])])
+
+  if test "x$ac_cv_has_babeltrace_header" != "xno"; then
+     # Check whether there is a function named 'lookup_enum' in
+     # babeltrace library.  We can't use the babeltrace library
+     # in which function 'lookup_enum' is defined.  This function
+     # is renamed to 'bt_lookup_name' in recent babeltrace.
+     AC_MSG_CHECKING([for broken babeltrace])
+     AC_TRY_LINK([#include <stdio.h>],
+     	[lookup_enum (NULL, NULL, 0)],
+	[AC_MSG_RESULT([yes]); LIBBABELTRACE= ; LIBBABELTRACE_CFLAGS= ],
+	[AC_MSG_RESULT([no]); AC_DEFINE(HAVE_LIBBABELTRACE, 1,
+	  [Define if libbabeltrace is available])])
+  else
+    LIBBABELTRACE=
+    LIBBABELTRACE_CFLAGS= 
+  fi
+
+  CFLAGS="$saved_CFLAGS"
+  LIBS="$saved_LIBS"
+fi
+
+# Flags needed for babeltrace.
+AC_SUBST(LIBBABELTRACE)
+AC_SUBST(LIBBABELTRACE_CFLAGS)
+
+
 # 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 909b769..ec35b17 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>
 
@@ -646,3 +647,743 @@ ctf_trace_file_writer_new (void)
 
   return (struct trace_file_writer *) 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 != NULL)
+    {
+      bt_ctf_iter_destroy (ctf_iter);
+      ctf_iter = NULL;
+    }
+  if (ctx != NULL)
+    {
+      bt_context_put (ctx);
+      ctx = NULL;
+    }
+}
+
+/* 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 == NULL)
+    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 == 0)
+    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;
+	}
+      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 != NULL && tp->base.loc)
+	{
+	  /* But don't try to guess if tracepoint is multi-location...  */
+	  if (tp->base.loc->next != NULL)
+	    {
+	      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 "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;
+	  uint16_t 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 (strcmp (name, "memory") != 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;
+	      int k;
+
+	      /*
+	      gdb_assert (mlen == bt_ctf_get_array_len (decl));
+	      contents = bt_ctf_get_char_array (array);
+	      */
+	      contents = xmalloc (mlen);
+
+	      for (k = 0; k < mlen; k++)
+		{
+		  const struct bt_definition *element
+		    = bt_ctf_get_index (event, array, k);
+
+		  contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+		}
+
+	      amt = (maddr + mlen) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      memcpy (readbuf, &contents[offset - maddr], amt);
+
+	      xfree (contents);
+
+	      /* 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.  */
+  if (exec_bfd != NULL)
+    {
+      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 == (int32_t) 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);
+
+  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 the address at which the current frame was collected.  */
+
+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);
+
+      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 != NULL)
+	*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 != NULL)
+		*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 "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 (strcmp (name, "memory") == 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 de59102..d224e14 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -126,14 +126,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.  */
@@ -141,10 +133,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;
@@ -3244,8 +3236,6 @@ static const struct trace_file_write_ops tfile_write_ops =
 #define TRACE_WRITE_V_BLOCK(writer, num, val)	\
   writer->ops->frame_ops->write_v_block ((writer), (num), (val))
 
-extern int trace_regblock_size;
-
 /* Save tracepoint data to file named FILENAME through WRITER.  WRITER
    determines the trace file format.  If TARGET_DOES_SAVE is non-zero,
    the save is performed on the target, otherwise GDB obtains all trace
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index ab11574..8762d1c 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,12 @@ struct trace_status *current_trace_status (void);
 
 extern char *default_collect;
 
+extern int tracepoint_number;
+
+extern int traceframe_number;
+
+extern int trace_regblock_size;
+
 /* 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]