From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30500 invoked by alias); 9 Apr 2013 08:53:31 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 30489 invoked by uid 89); 9 Apr 2013 08:53:30 -0000 X-Spam-SWARE-Status: No, score=-4.5 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP,TW_EG autolearn=ham version=3.3.1 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 09 Apr 2013 08:53:27 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1UPUIt-0004M6-9k from Yao_Qi@mentor.com ; Tue, 09 Apr 2013 01:53:23 -0700 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Tue, 9 Apr 2013 01:53:22 -0700 Received: from qiyao.dyndns.org (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Tue, 9 Apr 2013 01:53:20 -0700 Message-ID: <5163D6FE.1090106@codesourcery.com> Date: Tue, 09 Apr 2013 15:23:00 -0000 From: Yao Qi User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130110 Thunderbird/17.0.2 MIME-Version: 1.0 To: Doug Evans CC: Tom Tromey , gdb-patches Subject: Re: [PATCH v3 03/15] Read CTF by the ctf target References: <1362800844-27940-1-git-send-email-yao@codesourcery.com> <1362800844-27940-4-git-send-email-yao@codesourcery.com> <871ubjawq8.fsf@fleche.redhat.com> <20802.2886.914505.51784@ruffy2.mtv.corp.google.com> <51501E65.1020801@codesourcery.com> <20816.28886.574691.604457@ruffy2.mtv.corp.google.com> <51514D75.3070402@codesourcery.com> <20821.49407.164383.945535@ruffy2.mtv.corp.google.com> <51626EAC.3090208@codesourcery.com> <20834.63301.678122.134757@ruffy2.mtv.corp.google.com> In-Reply-To: <20834.63301.678122.134757@ruffy2.mtv.corp.google.com> Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-SW-Source: 2013-04/txt/msg00215.txt.bz2 On 04/09/2013 12:58 AM, Doug Evans wrote: >> + if (ret < 0) > > + { > > + ctf_destroy (); > > + error (_("Unable to use libbabeltrace open \"%s\""), dirname); > > The wording of this error message (here and below) is awkward. > I don't know libbabeltrace enough to know if this is accurate, but > it reads better. > > error (_("Unable to use libbabeltrace on \"%s\""), dirname); > > or > > error (_("Unable to use libbabeltrace on directory \"%s\""), dirname); I changed the message to error (_("Unable to use libbabeltrace on directory \"%s\""), dirname); > > Also, IWBN to add a more specific reason for the failure, > but I'm not sure how easy that would be. > Is there a bt_foo function akin to strerror? > Unfortunately, there isn't such function. > > + > > + 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); > > + > > Remove blank line. > > > +} Removed. > > + > > + 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); > > I don't know libbabeltrace, I'm assuming length can be at most 16 bits. > Right. "length" is defined as uint16_t in metadata, on the other hand, "length" is got from the remote target, which is 16-bit as well. > > + > > +/* This is the implementation of target_ops method to_traceframe_info. > > + 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; > > + > > + gdb_assert (ctf_iter != NULL); > > + /* 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); > > These days we prefer multi-line single statements for if/else/etc. > to be wrapped in braces. i.e., > > { > warning (_("Unhandled trace block type (%s) " > "while building trace frame info."), > name); > } > Fixed. I knew that single statement with comments should be warped by braces, like: if (foo) /* Comments. */ bar (); after reading GDB internals, I realize that "warning message in multiple lines" falls into this category as well. You are right. > > + > > +/* module initialization */ > > blank line > > > +void > > +_initialize_ctf (void) Fixed. -- Yao (齐尧) gdb: 2013-04-09 Hui Zhu Yao Qi * configure.ac: Check libbabeltrace is installed. * config.in: Regenerate. * configure: Regenerate. * Makefile.in (LIBBABELTRACE): New. (CLIBS): Add LIBBABELTRACE. * ctf.c (ctx, ctf_iter, trace_dirname): New. (ctf_destroy, 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_stack): New. (ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New. (_initialize_ctf): New. * tracepoint.c (get_tracepoint_number): New (struct traceframe_info, trace_regblock_size): Move it to ... * tracepoint.h: ... here. (get_tracepoint_number): Declare it. --- gdb/Makefile.in | 6 +- gdb/config.in | 3 + gdb/configure | 517 +++++++++++++++++++++++++++++++++++++ gdb/configure.ac | 41 +++ gdb/ctf.c | 754 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/tracepoint.c | 16 +- gdb/tracepoint.h | 13 + 7 files changed, 1339 insertions(+), 11 deletions(-) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 498d42a..0814bcb 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -154,6 +154,10 @@ 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@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -475,7 +479,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 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 0dd67f0..6588c72 100755 --- a/gdb/configure +++ b/gdb/configure @@ -592,6 +592,9 @@ enable_option_checking=no ac_subst_vars='LTLIBOBJS LIBOBJS GDB_NM_FILE +LTLIBBABELTRACE +LIBBABELTRACE +HAVE_LIBBABELTRACE frags target_subdir CONFIG_UNINSTALL @@ -819,6 +822,8 @@ with_x enable_sim enable_multi_ice enable_gdbserver +with_babeltrace +with_libbabeltrace_prefix ' ac_precious_vars='build_alias host_alias @@ -1532,6 +1537,9 @@ 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 include babeltrace support (auto/yes/no) + --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib + --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir Some influential environment variables: CC C compiler command @@ -14093,6 +14101,515 @@ 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 + +# Check whether --with-babeltrace was given. +if test "${with_babeltrace+set}" = set; then : + withval=$with_babeltrace; +else + with_babeltrace=auto +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5 +$as_echo_n "checking whether to use babeltrace... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5 +$as_echo "$with_babeltrace" >&6; } + +if test "x$with_babeltrace" = "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5 +$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;} +else + # Append -Werror to CFLAGS so that configure can catch the warning + # "assignment from incompatible pointer type", which is related to + # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works + # in GDB, while babeltrace 1.0.3 is broken. + # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be + # safe to save and restore CFLAGS here. + saved_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror" + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libbabeltrace-prefix was given. +if test "${with_libbabeltrace_prefix+set}" = set; then : + withval=$with_libbabeltrace_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi + +fi + + LIBBABELTRACE= + LTLIBBABELTRACE= + INCBABELTRACE= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='babeltrace babeltrace-ctf' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBBABELTRACE; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$hardcode_direct" = yes; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBBABELTRACE; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so" + else + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a" + else + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCBABELTRACE; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBBABELTRACE; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBBABELTRACE; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep" + LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep" + ;; + esac + done + fi + else + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name" + LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir" + done + fi + + + ac_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCBABELTRACE; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5 +$as_echo_n "checking for libbabeltrace... " >&6; } +if test "${ac_cv_libbabeltrace+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIBBABELTRACE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include +int +main () +{ +struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL)); + struct bt_ctf_event *event = NULL; + const struct bt_definition *scope; + + scope = bt_ctf_get_top_level_scope (event, + BT_STREAM_EVENT_HEADER); + bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id")); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_libbabeltrace=yes +else + ac_cv_libbabeltrace=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5 +$as_echo "$ac_cv_libbabeltrace" >&6; } + if test "$ac_cv_libbabeltrace" = yes; then + HAVE_LIBBABELTRACE=yes + +$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5 +$as_echo_n "checking how to link with libbabeltrace... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5 +$as_echo "$LIBBABELTRACE" >&6; } + else + HAVE_LIBBABELTRACE=no + CPPFLAGS="$ac_save_CPPFLAGS" + LIBBABELTRACE= + LTLIBBABELTRACE= + fi + + + + + + + CFLAGS=$saved_CFLAGS + + if test "$HAVE_LIBBABELTRACE" != yes; then + if test "$with_babeltrace" = yes; then + as_fn_error "babeltrace is missing or unusable" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5 +$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;} + fi + fi +fi + # 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 c17f587..149ac37 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -2321,6 +2321,47 @@ 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 +AC_ARG_WITH(babeltrace, + AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]), + [], [with_babeltrace=auto]) +AC_MSG_CHECKING([whether to use babeltrace]) +AC_MSG_RESULT([$with_babeltrace]) + +if test "x$with_babeltrace" = "xno"; then + AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.]) +else + # Append -Werror to CFLAGS so that configure can catch the warning + # "assignment from incompatible pointer type", which is related to + # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works + # in GDB, while babeltrace 1.0.3 is broken. + # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be + # safe to save and restore CFLAGS here. + saved_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Werror" + AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf], + [#include + #include + #include ], + [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL)); + struct bt_ctf_event *event = NULL; + const struct bt_definition *scope; + + scope = bt_ctf_get_top_level_scope (event, + BT_STREAM_EVENT_HEADER); + bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id")); + ]) + CFLAGS=$saved_CFLAGS + + if test "$HAVE_LIBBABELTRACE" != yes; then + if test "$with_babeltrace" = yes; then + AC_MSG_ERROR([babeltrace is missing or unusable]) + else + AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.]) + fi + fi +fi + # 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 de54051..1829aa8 100644 --- a/gdb/ctf.c +++ b/gdb/ctf.c @@ -24,6 +24,7 @@ #include "tracepoint.h" #include "regcache.h" #include "gdb_stat.h" +#include "exec.h" #include @@ -670,3 +671,756 @@ ctf_trace_file_writer_new (void) return (struct trace_file_writer *) writer; } + +#if 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 +#include +#include + +/* 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; + +/* Destroy ctf iterator and context. */ + +static void +ctf_destroy (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 create bt_context")); + ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL); + if (ret < 0) + { + ctf_destroy (); + error (_("Unable to use libbabeltrace on directory \"%s\""), + dirname); + } + + begin_pos.type = BT_SEEK_BEGIN; + ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL); + if (ctf_iter == NULL) + { + ctf_destroy (); + error (_("Unable to create bt_iterator")); + } + + /* 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); +} + +/* This is the implementation of target_ops method to_open. Open CTF + trace data, read trace status, trace state variables and tracepoint + definitions from the first packet. Set the start position at the + second packet which contains events on trace blocks. */ + +static void +ctf_open (char *dirname, int from_tty) +{ + if (!dirname) + error (_("No CTF directory specified.")); + + ctf_open_dir (dirname); + + target_preopen (from_tty); + trace_dirname = xstrdup (dirname); + push_target (&ctf_ops); +} + +/* This is the implementation of target_ops method to_close. Destroy + CTF iterator and context. */ + +static void +ctf_close (void) +{ + ctf_destroy (); + xfree (trace_dirname); + trace_dirname = NULL; +} + +/* This is the implementation of target_ops method to_files_info. + Print the directory name of CTF trace data. */ + +static void +ctf_files_info (struct target_ops *t) +{ + printf_filtered ("\t`%s'\n", trace_dirname); +} + +/* This is the implementation of target_ops method to_fetch_registers. + 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; + + gdb_assert (ctf_iter != NULL); + /* 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 (get_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); + } + } +} + +/* This is the implementation of target_ops method to_xfer_partial. + 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 (get_traceframe_number () != -1) + { + struct bt_iter_pos *pos; + int i = 0; + + gdb_assert (ctf_iter != NULL); + /* 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 amt; + uint64_t maddr; + 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; + + 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; +} + +/* This is the implementation of target_ops method + to_get_trace_state_variable_value. + 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; + + gdb_assert (ctf_iter != NULL); + /* 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 (name == NULL || 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; + } + } + + 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 CORE_ADDR +ctf_get_traceframe_address (void) +{ + struct bt_ctf_event *event = NULL; + struct bt_iter_pos *pos; + CORE_ADDR addr = 0; + + gdb_assert (ctf_iter != NULL); + 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) + 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; +} + +/* This is the implementation of target_ops method to_trace_find. + 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, + CORE_ADDR addr1, CORE_ADDR 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; + } + + gdb_assert (ctf_iter != NULL); + /* 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) + break; + + if (strcmp (name, "frame") == 0) + { + CORE_ADDR 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 > get_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) + break; + } + + return -1; +} + +/* This is the implementation of target_ops method to_has_stack. + The target has a stack when GDB has already selected one trace + frame. */ + +static int +ctf_has_stack (struct target_ops *ops) +{ + return get_traceframe_number () != -1; +} + +/* This is the implementation of target_ops method to_has_registers. + The target has registers when GDB has already selected one trace + frame. */ + +static int +ctf_has_registers (struct target_ops *ops) +{ + return get_traceframe_number () != -1; +} + +/* This is the implementation of target_ops method to_traceframe_info. + 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; + + gdb_assert (ctf_iter != NULL); + /* 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); + + return info; +} + +static void +init_ctf_ops (void) +{ + memset (&ctf_ops, 0, sizeof (ctf_ops)); + + 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_stack = ctf_has_stack; + ctf_ops.to_has_registers = ctf_has_registers; + ctf_ops.to_traceframe_info = ctf_traceframe_info; + ctf_ops.to_magic = OPS_MAGIC; +} + +#endif + +/* -Wmissing-prototypes */ + +extern initialize_file_ftype _initialize_ctf; + +/* module initialization */ + +void +_initialize_ctf (void) +{ +#if HAVE_LIBBABELTRACE + init_ctf_ops (); + + add_target (&ctf_ops); +#endif +} diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 3d8b131..962e632 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -127,14 +127,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. */ @@ -3303,8 +3295,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 @@ -3741,6 +3731,12 @@ get_traceframe_number (void) return traceframe_number; } +int +get_tracepoint_number (void) +{ + return tracepoint_number; +} + /* Make the traceframe NUM be the current trace frame. Does nothing if NUM is already current. */ diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index 8df906f..378824e 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,8 @@ struct trace_status *current_trace_status (void); extern char *default_collect; +extern int trace_regblock_size; + /* Struct to collect random info about tracepoints on the target. */ struct uploaded_tp @@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty); /* Returns the current traceframe number. */ extern int get_traceframe_number (void); +/* Returns the tracepoint number for current traceframe. */ +extern int get_tracepoint_number (void); + /* Make the traceframe NUM be the current GDB trace frame number, and do nothing more. In particular, this does not flush the register/frame caches or notify the target about the trace frame -- 1.7.7.6