Re: [PATCH 3/5] Read CTF by the ctf target

Yao Qi
2013-03-03T10:39:20Z

[-- Attachment #1: Type: text/plain, Size: 2360 bytes --]

On 03/01/2013 11:50 PM, Tom Tromey wrote:
>
> Yao> + /* xfree (regs); */
>
> It seems like this should be deleted.
> I don't really know, though.

It can be removed.

>
> Yao> + unsigned short mlen;
>
> I'm curious about the rationale for the type here.

Its type should "uint16_t", because ....

> And a bit later:
>
> Yao> + mlen = (uint16_t) bt_ctf_get_uint64 (def);
>
> Why use uint16_t here and not mlen's real type?
> But I don't understand why this has a shorter type anyhow.
>

... the length of contents is 2-bytes, so we choose "uint16_t" for its type.

> Yao> + /* It's unduly pedantic to refuse to look at the executable for
> Yao> + read-only pieces; so do the equivalent of readonly regions aka
> Yao> + QTro packet. */
> Yao> + /* FIXME account for relocation at some point. */
>
> There's a rule against adding new FIXME comments. Sometimes I think
> maybe we're too strict about this; though in practice it does seem to me
> that these are rarely fixed for their own sake, but instead just as a
> side effect of something else.

Some code are copied from the tfile target (tracepoint.c). This FIXME
(and the one below) is copied from tfile target as well. My original
plan is to share some code between tfile target and ctf target after ctf
target patch goes in, as both of them are about reading trace data from
file. So I didn't pay much attention on these comments.

>
> I suppose you could rephrase it to be a note.
> Or is it fixable? It isn't clear to me in what situation this code is
> invoked.
>

Neither do I. It is beyond my knowledge to give an accurate comment or
note here, so I remove this FIXME. My next step is to get rid of the
duplication (including these comments and FIXMEs) of tfile target and
ctf target. We may need other patches to address these FIXMEs separately.

> I was curious why this looks directly at the exec_bfd rather than using
> something like ALL_OBJFILE_OSECTIONS. It seemed like this might help
> with the relocation problem.
>
> Yao> + if (exec_bfd)
>
> A while ago we agreed to use the more explicit `exec_bfd != NULL' form.

Fixed.

>
> Yao> + /* Didn't find anything. */
> Yao> + return found;
>
> I think this can be reached in the "did find something" case as well, so
> I suggest just dropping the comment.

This line is removed.

--
Yao (é½å°§)

[-- Attachment #2: 0003-Read-CTF-by-the-ctf-target.patch --]
[-- Type: text/x-patch, Size: 32650 bytes --]

From 9171e512d75495adc6cf2bc9368cbe70c6068307 Mon Sep 17 00:00:00 2001
From: Yao Qi <yao@codesourcery.com>
Date: Tue, 26 Feb 2013 17:35:53 +0800
Subject: [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-03-03 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 | 727 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 14 +-
gdb/tracepoint.h | 14 +
7 files changed, 978 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..1bb5d3e 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_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..9e88cd2 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_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 c243fd2..1e35780 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>

@@ -707,3 +708,729 @@ 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)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx)
+ {
+ 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)
+ 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;
+ }
+ 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;
+ 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 (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. */
+ 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 == (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);
+
+ 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)
+ *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 eab4043..f62c90e 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;
@@ -3258,8 +3250,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 67a7b87..8aa7d02 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