diff options
author | Dave Brolley <brolley@redhat.com> | 2009-08-04 12:35:41 -0400 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-08-04 12:35:41 -0400 |
commit | bc9077d171b8250a93a1b5a481e34913e5585dd5 (patch) | |
tree | 1fa945c76a66e297e783354ccd7a860aa65d304b | |
parent | 3174c3ca37371d738b86d630dc4d8b15104e57d0 (diff) | |
parent | 8b095b454b34e88c04592be6c651153f802eced6 (diff) | |
download | systemtap-steved-bc9077d171b8250a93a1b5a481e34913e5585dd5.tar.gz systemtap-steved-bc9077d171b8250a93a1b5a481e34913e5585dd5.tar.xz systemtap-steved-bc9077d171b8250a93a1b5a481e34913e5585dd5.zip |
Merge branch 'master' of git://sources.redhat.com/git/systemtap
Conflicts:
cache.cxx
63 files changed, 3356 insertions, 1645 deletions
diff --git a/Makefile.am b/Makefile.am index 37491eef..c2234d1c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ AUTOMAKE_OPTIONS = no-dist foreign pkglibexecdir = ${libexecdir}/${PACKAGE} oldincludedir = ${includedir}/sys -AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"' +AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"' -I$(srcdir)/includes AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wunused -Wformat=2 -W AM_CXXFLAGS = -Wall -Werror diff --git a/Makefile.in b/Makefile.in index 9410eaae..a1b45add 100644 --- a/Makefile.in +++ b/Makefile.in @@ -358,7 +358,7 @@ top_srcdir = @top_srcdir@ # we don't maintain a ChangeLog, which makes us non-GNU -> foreign AUTOMAKE_OPTIONS = no-dist foreign -AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"' +AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"' -I$(srcdir)/includes AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wunused -Wformat=2 -W AM_CXXFLAGS = -Wall -Werror man_MANS = stapprobes.3stap stapfuncs.3stap stapvars.3stap \ @@ -3,6 +3,9 @@ - Systemwide kernel .function.return (kretprobe) maxactive defaults may be overridden with the -DKRETACTIVE=nnn parameter. +- Translation pass 2 is significantly faster by avoiding unnecessary + searching through a kernel build/module directory tree. + * What's new in version 0.9.8 - Miscellaneous new tapset functions: @@ -10,6 +10,7 @@ #include "session.h" #include "cache.h" #include "util.h" +#include "sys/sdt.h" #include <cerrno> #include <string> #include <fstream> @@ -59,6 +60,7 @@ add_to_cache(systemtap_session& s) } string module_src_path = s.tmpdir + "/" + s.module_name + ".ko"; + STAP_PROBE2(stap, cache__add__module, module_src_path.c_str(), s.hash_path.c_str()); if (s.verbose > 1) clog << "Copying " << module_src_path << " to " << s.hash_path << endl; if (copy_file(module_src_path.c_str(), s.hash_path.c_str()) != 0) @@ -81,6 +83,7 @@ add_to_cache(systemtap_session& s) if (file_exists (module_signature_src_path)) { + STAP_PROBE2(stap, cache__add__nss, module_signature_src_path.c_str(), module_signature_dest_path.c_str()); if (s.verbose > 1) clog << "Copying " << module_signature_src_path << " to " << module_signature_dest_path << endl; if (copy_file(module_signature_src_path.c_str(), module_signature_dest_path.c_str()) != 0) @@ -100,6 +103,7 @@ add_to_cache(systemtap_session& s) c_dest_path.resize(c_dest_path.size() - 3); c_dest_path += ".c"; + STAP_PROBE2(stap, cache__add__source, s.translated_source.c_str(), c_dest_path.c_str()); if (s.verbose > 1) clog << "Copying " << s.translated_source << " to " << c_dest_path << endl; @@ -244,6 +248,8 @@ get_from_cache(systemtap_session& s) clog << "Pass 4: using cached " << s.hash_path << endl; } + STAP_PROBE2(stap, cache__get, c_src_path.c_str(), s.hash_path.c_str()); + return true; } @@ -344,6 +350,7 @@ clean_cache(systemtap_session& s) if ( (r_cache_size / 1024 / 1024) < cache_mb_max) //convert r_cache_size to MiB break; + STAP_PROBE1(stap, cache__clean, (i->path).c_str()); //remove this (*i) cache_entry, add to removed list i->unlink(); r_cache_size -= i->size; @@ -637,7 +637,9 @@ ac_includes_default="\ #endif" enable_option_checking=no -ac_subst_vars='LTLIBOBJS +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS LIBOBJS subdirs CXXCPP @@ -1943,7 +1945,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -am__api_version='1.10' +am__api_version='1.11' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do @@ -2074,16 +2076,33 @@ $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + { { $as_echo "$as_me:$LINENO: error: unsafe absolute working directory name" >&5 +$as_echo "$as_me: error: unsafe absolute working directory name" >&2;} + { (exit 1); exit 1; }; };; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + { { $as_echo "$as_me:$LINENO: error: unsafe srcdir value: \`$srcdir'" >&5 +$as_echo "$as_me: error: unsafe srcdir value: \`$srcdir'" >&2;} + { (exit 1); exit 1; }; };; +esac + # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` + set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ @@ -2127,7 +2146,14 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " @@ -2137,6 +2163,115 @@ else $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + { $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then @@ -2319,108 +2454,6 @@ AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} -install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} - -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:$LINENO: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:$LINENO: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. @@ -2433,6 +2466,7 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + { $as_echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. @@ -3414,7 +3448,7 @@ ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: - @echo done + @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. @@ -3425,24 +3459,24 @@ am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf -# We grep out `Entering directory' and `Leaving directory' -# messages which can occur if `w' ends up in MAKEFLAGS. -# In particular we don't look at `^make:' because GNU make might -# be invoked under some other name (usually "gmake"), in which -# case it prints its new name instead of `make'. -if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then - am__include=include - am__quote= - _am_result=GNU -fi +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf - if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then - am__include=.include - am__quote="\"" - _am_result=BSD - fi + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac fi @@ -3499,6 +3533,11 @@ else if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and @@ -3516,7 +3555,17 @@ else done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested @@ -3526,19 +3575,23 @@ else break fi ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; none) break ;; esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message @@ -3979,6 +4032,11 @@ else if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and @@ -3996,7 +4054,17 @@ else done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested @@ -4006,19 +4074,23 @@ else break fi ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; none) break ;; esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message @@ -5006,6 +5078,11 @@ else if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and @@ -5023,7 +5100,17 @@ else done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested @@ -5033,19 +5120,23 @@ else break fi ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; none) break ;; esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. if depmode=$depmode \ - source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message @@ -8854,7 +8945,7 @@ _ACEOF ac_config_headers="$ac_config_headers config.h:config.in" -ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap" +ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap man/stapprobes.snmp.3stap initscript/systemtap" @@ -8965,6 +9056,14 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then { { $as_echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&5 @@ -9596,6 +9695,7 @@ do "man/stapprobes.socket.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.socket.3stap" ;; "man/stapprobes.tcp.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.tcp.3stap" ;; "man/stapprobes.udp.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.udp.3stap" ;; + "man/stapprobes.snmp.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.snmp.3stap" ;; "initscript/systemtap") CONFIG_FILES="$CONFIG_FILES initscript/systemtap" ;; "run-stap") CONFIG_FILES="$CONFIG_FILES run-stap" ;; "run-staprun") CONFIG_FILES="$CONFIG_FILES run-staprun" ;; @@ -10254,27 +10354,28 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || # Autoconf 2.62 quotes --file arguments for eval, but not when files -# are listed without --file. Let's play safe and only enable the eval -# if we detect the quoting. -case $CONFIG_FILES in -*\'*) eval set x "$CONFIG_FILES" ;; -*) set x $CONFIG_FILES ;; -esac -shift -for mf -do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`$as_dirname -- "$mf" || + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ @@ -10297,28 +10398,28 @@ $as_echo X"$mf" | q } s/.*/./; q'` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`$as_dirname -- "$file" || + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ @@ -10341,7 +10442,7 @@ $as_echo X"$file" | q } s/.*/./; q'` - { as_dir=$dirpart/$fdir + { as_dir=$dirpart/$fdir case $as_dir in #( -*) as_dir=./$as_dir;; esac @@ -10382,10 +10483,11 @@ $as_echo X"$as_dir" | } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 $as_echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done done -done +} ;; "run-stap":F) chmod +x run-stap ;; "run-staprun":F) chmod +x run-staprun ;; diff --git a/doc/Makefile.in b/doc/Makefile.in index f7d902a7..996700ec 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -17,8 +18,9 @@ # Makefile.am --- automake input file for systemtap docs VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -40,6 +42,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ @@ -51,10 +54,38 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ @@ -190,9 +221,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu doc/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -210,6 +241,7 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -235,7 +267,7 @@ $(RECURSIVE_TARGETS): else \ local_target="$$target"; \ fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ @@ -269,16 +301,16 @@ $(RECURSIVE_CLEAN_TARGETS): else \ local_target="$$target"; \ fi; \ - (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) @@ -293,7 +325,7 @@ tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ @@ -305,7 +337,7 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ - tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -314,29 +346,34 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -357,29 +394,44 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done - list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ - distdir=`$(am__cd) $(distdir) && pwd`; \ - top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ - (cd $$subdir && \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$top_distdir" \ - distdir="$$distdir/$$subdir" \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ + am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ @@ -410,6 +462,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -431,6 +484,8 @@ dvi-am: html: html-recursive +html-am: + info: info-recursive info-am: @@ -438,21 +493,30 @@ info-am: install-data-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook - install-dvi: install-dvi-recursive +install-dvi-am: + install-exec-am: install-html: install-html-recursive +install-html-am: + install-info: install-info-recursive +install-info-am: + install-man: install-pdf: install-pdf-recursive +install-pdf-am: + install-ps: install-ps-recursive +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-recursive @@ -473,8 +537,8 @@ ps-am: uninstall-am: uninstall-local -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ - install-data-am install-strip +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-data-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am all-local check check-am clean clean-generic \ @@ -520,6 +584,7 @@ uninstall-am: uninstall-local latex -output-directory=$$pwd $<; \ latex -output-directory=$$pwd $<; \ latex -output-directory=$$pwd $< + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/doc/SystemTap_Beginners_Guide/en-US/extras/stapprep.sh b/doc/SystemTap_Beginners_Guide/en-US/extras/stapprep.sh index 6905c9cc..3c6bf785 100755 --- a/doc/SystemTap_Beginners_Guide/en-US/extras/stapprep.sh +++ b/doc/SystemTap_Beginners_Guide/en-US/extras/stapprep.sh @@ -26,6 +26,10 @@ if [ "$NEEDED" != "" ]; then echo -e "Need to install the following packages:\n$NEEDED" if [ `id -u` = "0" ]; then #attempt download and install DIR=`mktemp -d` || exit 1 + if [ ! -x /usr/bin/yumdownloader ]; then + echo "Need to first install yum-utils for yumdownloader" + yum install -y yum-utils + fi yumdownloader --enablerepo="*debuginfo*" $NEEDED --destdir=$DIR check_error $? "problem downloading rpm(s) $NEEDED" rpm --force -ivh $DIR/*.rpm diff --git a/doc/SystemTap_Tapset_Reference/Makefile.in b/doc/SystemTap_Tapset_Reference/Makefile.in index 82217f3a..2368ccad 100644 --- a/doc/SystemTap_Tapset_Reference/Makefile.in +++ b/doc/SystemTap_Tapset_Reference/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -18,8 +19,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -42,6 +44,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) docproc_SOURCES = docproc.c docproc_OBJECTS = docproc.$(OBJEXT) @@ -49,6 +52,7 @@ docproc_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -195,9 +199,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/SystemTap_Tapset_Reference/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu doc/SystemTap_Tapset_Reference/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/SystemTap_Tapset_Reference/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/SystemTap_Tapset_Reference/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -215,6 +219,7 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) @@ -232,14 +237,14 @@ distclean-compile: .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` @@ -256,7 +261,7 @@ tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -264,29 +269,34 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -307,13 +317,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -341,6 +355,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -362,6 +377,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -369,21 +386,30 @@ info-am: install-data-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook - install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -452,6 +478,7 @@ uninstall-am: @BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) man3/* $(MAN_INSTALL_DIR) @BUILD_REFDOCS_TRUE@ $(MKDIR_P) $(HTML_INSTALL_DIR) @BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) tapsets/* $(HTML_INSTALL_DIR) + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: @@ -137,6 +137,7 @@ i = 1 build_header = False build_source = False add_typedefs = False +h_ext = '.h' filename = "" while (i < len (sys.argv)): if (sys.argv[i] == "-o"): @@ -148,7 +149,6 @@ while (i < len (sys.argv)): elif (sys.argv[i] == "-h"): build_header = True elif (sys.argv[i] == "-G"): - build_header = True build_source = True elif (sys.argv[i] == "--types"): add_typedefs = True @@ -162,22 +162,23 @@ if (build_header == False and build_source == False): if (filename == ""): if (s_filename != ""): (filename,ext) = os.path.splitext(s_filename) - filename = os.path.basename(filename) else: usage sys.exit(1) else: - (filename,ext) = os.path.splitext(filename) - + if (build_header): + h_ext = "" + else: + (filename,ext) = os.path.splitext(filename) if (build_header): providers = provider() - providers.generate(s_filename, filename + ".h", add_typedefs) -if (build_source): + providers.generate(s_filename, filename + h_ext, add_typedefs) +elif (build_source): (basename,ext) = os.path.splitext(s_filename) basename = os.path.basename(basename) (d,fn) = mkstemp(suffix=".c",prefix=basename) f = open(fn,mode='w') - f.write("#include \"" + filename + ".h\"\nstatic __dtrace () {}\n") + f.write("static __dtrace () {}\n") f.close() - call(["gcc", "-fPIC", "-I.", "-I@prefix@/include", "-g", "-c", fn, "-o", filename + ".o"], shell=False) + call(["gcc", "-fPIC", "-I.", "-I@prefix@/include", "-g", "-c", fn, "-o", os.path.basename(filename) + ".o"], shell=False) os.remove(fn) @@ -124,7 +124,7 @@ dwflpp::get_module_dwarf(bool required, bool report) if (required) throw semantic_error (msg); - else + else if (! sess.suppress_warnings) cerr << "WARNING: " << msg << "\n"; } } @@ -808,19 +808,43 @@ dwflpp::iterate_over_srcfile_lines (char const * srcfile, } else if (line_type == WILDCARD) function_line (&lineno); + else if (line_type == RANGE) { /* correct lineno */ + int start_lineno; + + function_line (&start_lineno); + lineno = lineno < start_lineno ? start_lineno : lineno; + if (lineno > lines[1]) { /* invalid line range */ + stringstream advice; + advice << "Invalid line range (" << lines[0] << "-" << lines[1] << ")"; + if (start_lineno > lines[1]) + advice << ", the end line number " << lines[1] << " < " << start_lineno; + throw semantic_error (advice.str()); + } + } + for (int l = lineno; ; l = l + 1) { set<int> lines_probed; pair<set<int>::iterator,bool> line_probed; - dwarf_assert ("dwarf_getsrc_file", - dwarf_getsrc_file (module_dwarf, - srcfile, l, 0, - &srcsp, &nsrcs)); + int ret = 0; + + ret = dwarf_getsrc_file (module_dwarf, srcfile, l, 0, + &srcsp, &nsrcs); + if (line_type != WILDCARD && line_type != RANGE) + dwarf_assert ("dwarf_getsrc_file", ret); + if (line_type == WILDCARD || line_type == RANGE) { Dwarf_Addr line_addr; + + if (ret != 0) /* tolerate invalid line number */ + break; + dwarf_lineno (srcsp [0], &lineno); + /* Maybe lineno will exceed the input end */ + if (line_type == RANGE && lineno > lines[1]) + break; line_probed = lines_probed.insert(lineno); if (lineno != l || line_probed.second == false || nsrcs > 1) continue; @@ -1596,9 +1620,8 @@ dwflpp::print_members(Dwarf_Die *vardie, ostream &o) bool -dwflpp::find_struct_member(const string& member, +dwflpp::find_struct_member(const target_symbol::component& c, Dwarf_Die *parentdie, - const target_symbol *e, Dwarf_Die *memberdie, vector<Dwarf_Attribute>& locs) { @@ -1616,7 +1639,7 @@ dwflpp::find_struct_member(const string& member, throw semantic_error (string (dwarf_tag(&die) == DW_TAG_union_type ? "union" : "struct") + string (dwarf_diename_integrate (&die) ?: "<anonymous>") + string (dwarf_errmsg (-1)), - e->tok); + c.tok); } do @@ -1634,10 +1657,10 @@ dwflpp::find_struct_member(const string& member, !dwarf_formref_die (&attr, &subdie)) continue; - if (find_struct_member(member, &subdie, e, memberdie, locs)) + if (find_struct_member(c, &subdie, memberdie, locs)) goto success; } - else if (name == member) + else if (name == c.member) { *memberdie = die; goto success; @@ -1656,9 +1679,9 @@ success: /* Union members don't usually have a location, * but just use the containing union's location. */ else if (dwarf_tag(parentdie) != DW_TAG_union_type) - throw semantic_error ("no location for field '" + member + throw semantic_error ("no location for field '" + c.member + "': " + string(dwarf_errmsg (-1)), - e->tok); + c.tok); return true; } @@ -1685,6 +1708,8 @@ dwflpp::translate_components(struct obstack *pool, while (i < e->components.size()) { + const target_symbol::component& c = e->components[i]; + /* XXX: This would be desirable, but we don't get the target_symbol token, and printing that gives us the file:line number too early anyway. */ #if 0 @@ -1706,39 +1731,53 @@ dwflpp::translate_components(struct obstack *pool, case DW_TAG_pointer_type: c_translate_pointer (pool, 1, 0 /* PR9768*/, die, tail); - if (e->components[i].first != target_symbol::comp_literal_array_index) + if (c.type != target_symbol::comp_literal_array_index && + c.type != target_symbol::comp_expression_array_index) break; /* else fall through as an array access */ case DW_TAG_array_type: - if (e->components[i].first == target_symbol::comp_literal_array_index) + if (c.type == target_symbol::comp_literal_array_index) { c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, - NULL, lex_cast<Dwarf_Word>(e->components[i].second)); + NULL, c.num_index); + ++i; + } + else if (c.type == target_symbol::comp_expression_array_index) + { + string index = "THIS->index" + lex_cast<string>(i); + c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, + index.c_str(), 0); ++i; } else - throw semantic_error("bad field '" - + e->components[i].second - + "' for array type", - e->tok); + throw semantic_error ("invalid access '" + + lex_cast<string>(c) + + "' for array type", + c.tok); break; case DW_TAG_structure_type: case DW_TAG_union_type: + if (c.type != target_symbol::comp_struct_member) + throw semantic_error ("invalid access '" + + lex_cast<string>(c) + + "' for struct/union type", + c.tok); + if (dwarf_hasattr(die, DW_AT_declaration)) { Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); if (tmpdie == NULL) throw semantic_error ("unresolved struct " + string (dwarf_diename_integrate (die) ?: "<anonymous>"), - e->tok); + c.tok); *die_mem = *tmpdie; } { vector<Dwarf_Attribute> locs; - if (!find_struct_member(e->components[i].second, die, e, die, locs)) + if (!find_struct_member(c, die, die, locs)) { string alternatives; stringstream members; @@ -1746,10 +1785,10 @@ dwflpp::translate_components(struct obstack *pool, if (members.str().size() != 0) alternatives = " (alternatives:" + members.str(); throw semantic_error("unable to find member '" + - e->components[i].second + "' for struct " + c.member + "' for struct " + string(dwarf_diename_integrate(die) ?: "<unknown>") + alternatives, - e->tok); + c.tok); } for (unsigned j = 0; j < locs.size(); ++j) @@ -1760,39 +1799,41 @@ dwflpp::translate_components(struct obstack *pool, break; case DW_TAG_enumeration_type: - throw semantic_error ("field '" - + e->components[i].second + throw semantic_error ("invalid access '" + + lex_cast<string>(c) + "' vs. enum type " + string(dwarf_diename_integrate (die) ?: "<anonymous type>"), - e->tok); + c.tok); break; case DW_TAG_base_type: - throw semantic_error ("field '" - + e->components[i].second + throw semantic_error ("invalid access '" + + lex_cast<string>(c) + "' vs. base type " + string(dwarf_diename_integrate (die) ?: "<anonymous type>"), - e->tok); + c.tok); break; case -1: throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)), - e->tok); + c.tok); break; default: throw semantic_error (string(dwarf_diename_integrate (die) ?: "<anonymous type>") + ": unexpected type tag " + lex_cast<string>(dwarf_tag (die)), - e->tok); + c.tok); break; } /* Now iterate on the type in DIE's attribute. */ if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) - throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), e->tok); + throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), + c.tok); } /* For an array index, we need to dereference the final DIE */ - if (e->components.back().first == target_symbol::comp_literal_array_index) + if (e->components.back().type == target_symbol::comp_literal_array_index || + e->components.back().type == target_symbol::comp_expression_array_index) die = dwarf_formref_die (attr_mem, die_mem); return die; @@ -333,9 +333,8 @@ private: struct location **tail, const target_symbol *e); - bool find_struct_member(const std::string& member, + bool find_struct_member(const target_symbol::component& c, Dwarf_Die *parentdie, - const target_symbol *e, Dwarf_Die *memberdie, std::vector<Dwarf_Attribute>& locs); diff --git a/elaborate.cxx b/elaborate.cxx index 88c5deb9..93500239 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1129,7 +1129,7 @@ semantic_pass_symbols (systemtap_session& s) try { for (unsigned j=0; j<s.code_filters.size(); j++) - fd->body = s.code_filters[j]->require (fd->body); + s.code_filters[j]->replace (fd->body); sym.current_function = fd; sym.current_probe = 0; @@ -1164,7 +1164,7 @@ semantic_pass_symbols (systemtap_session& s) try { for (unsigned k=0; k<s.code_filters.size(); k++) - dp->body = s.code_filters[k]->require (dp->body); + s.code_filters[k]->replace (dp->body); sym.current_function = 0; sym.current_probe = dp; @@ -2157,8 +2157,8 @@ struct dead_assignment_remover: public update_visitor void dead_assignment_remover::visit_assignment (assignment* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); symbol* left = get_symbol_within_expression (e->left); vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target @@ -2224,10 +2224,10 @@ void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p) // This instance may be reused for multiple probe/function body trims. for (unsigned i=0; i<s.probes.size(); i++) - s.probes[i]->body = dar.require (s.probes[i]->body); + dar.replace (s.probes[i]->body); for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) - it->second->body = dar.require (it->second->body); + dar.replace (it->second->body); // The rewrite operation is performed within the visitor. // XXX: we could also zap write-only globals here @@ -2311,8 +2311,8 @@ dead_stmtexpr_remover::visit_block (block *s) void dead_stmtexpr_remover::visit_if_statement (if_statement *s) { - s->thenblock = require (s->thenblock, true); - s->elseblock = require (s->elseblock, true); + replace (s->thenblock, true); + replace (s->elseblock, true); if (s->thenblock == 0) { @@ -2364,7 +2364,7 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) void dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s) { - s->block = require(s->block, true); + replace (s->block, true); if (s->block == 0) { @@ -2378,7 +2378,7 @@ dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s) void dead_stmtexpr_remover::visit_for_loop (for_loop *s) { - s->block = require(s->block, true); + replace (s->block, true); if (s->block == 0) { @@ -2467,7 +2467,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) duv.focal_vars.insert (p->locals.begin(), p->locals.end()); - p->body = duv.require(p->body, true); + duv.replace (p->body, true); if (p->body == 0) { if (! s.suppress_warnings @@ -2493,7 +2493,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) duv.focal_vars.insert (s.globals.begin(), s.globals.end()); - fn->body = duv.require(fn->body, true); + duv.replace (fn->body, true); if (fn->body == 0) { if (! s.suppress_warnings) @@ -2555,6 +2555,7 @@ struct void_statement_reducer: public update_visitor void visit_concatenation (concatenation* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); + void visit_target_symbol (target_symbol* e); void visit_cast_op (cast_op* e); // these are a bit hairy to grok due to the intricacies of indexables and @@ -2576,7 +2577,7 @@ struct void_statement_reducer: public update_visitor void void_statement_reducer::visit_expr_statement (expr_statement* s) { - s->value = require (s->value, true); + replace (s->value, true); // if the expression provides 0, that's our signal that a new // statement has been provided, so we shouldn't provide this one. @@ -2588,8 +2589,8 @@ void void_statement_reducer::visit_if_statement (if_statement* s) { // s->condition is never void - s->thenblock = require (s->thenblock); - s->elseblock = require (s->elseblock); + replace (s->thenblock); + replace (s->elseblock); provide (s); } @@ -2597,7 +2598,7 @@ void void_statement_reducer::visit_for_loop (for_loop* s) { // s->init/cond/incr are never void - s->block = require (s->block); + replace (s->block); provide (s); } @@ -2605,7 +2606,7 @@ void void_statement_reducer::visit_foreach_loop (foreach_loop* s) { // s->indexes/base/limit are never void - s->block = require (s->block); + replace (s->block); provide (s); } @@ -2824,16 +2825,73 @@ void_statement_reducer::visit_print_format (print_format* e) } void +void_statement_reducer::visit_target_symbol (target_symbol* e) +{ + // When target_symbol isn't needed, it's just as good to + // evaluate any array indexes directly + + block *b = new block; + b->tok = e->tok; + + for (unsigned i=0; i<e->components.size(); i++ ) + { + if (e->components[i].type != target_symbol::comp_expression_array_index) + continue; + + expr_statement *es = new expr_statement; + es->value = e->components[i].expr_index; + es->tok = es->value->tok; + b->statements.push_back(es); + } + + if (b->statements.empty()) + { + delete b; + provide (e); + return; + } + + if (session.verbose>2) + clog << "Eliding unused target symbol " << *e->tok << endl; + + b->visit(this); + relaxed_p = false; + e = 0; + provide (e); +} + +void void_statement_reducer::visit_cast_op (cast_op* e) { // When the result of a cast operation isn't needed, it's just as good to - // evaluate the operand directly + // evaluate the operand and any array indexes directly + + block *b = new block; + b->tok = e->tok; + + expr_statement *es = new expr_statement; + es->value = e->operand; + es->tok = es->value->tok; + b->statements.push_back(es); + + for (unsigned i=0; i<e->components.size(); i++ ) + { + if (e->components[i].type != target_symbol::comp_expression_array_index) + continue; + + es = new expr_statement; + es->value = e->components[i].expr_index; + es->tok = es->value->tok; + b->statements.push_back(es); + } if (session.verbose>2) clog << "Eliding unused typecast " << *e->tok << endl; + b->visit(this); relaxed_p = false; - e->operand->visit(this); + e = 0; + provide (e); } @@ -2847,10 +2905,10 @@ void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) vuv.focal_vars.insert (s.globals.begin(), s.globals.end()); for (unsigned i=0; i<s.probes.size(); i++) - s.probes[i]->body = vuv.require (s.probes[i]->body); + vuv.replace (s.probes[i]->body); for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) - it->second->body = vuv.require (it->second->body); + vuv.replace (it->second->body); } diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx new file mode 100644 index 00000000..1fa598c2 --- /dev/null +++ b/grapher/Graph.cxx @@ -0,0 +1,262 @@ +#include "Graph.hxx" + +#include <sstream> +#include <iostream> +#include <iomanip> + +namespace systemtap +{ + using namespace std; + using namespace std::tr1; + + Graph::Graph() + : _left(0.0), _right(1.0), _top(5.0), _bottom(0.0), _lineWidth(2), + _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0), + _playButton(new CairoPlayButton) + { + } + + + void Graph::draw(Cairo::RefPtr<Cairo::Context> cr) + { + + if (_autoScaling) + { + // line separation + int linesPossible = _graphWidth / (_lineWidth + 2); + // Find latest time. + double latestTime = 0; + for (DatasetList::iterator ditr = _datasets.begin(), + de = _datasets.end(); + ditr != de; + ++ditr) + { + if (!(*ditr)->times.empty()) + { + double lastDataTime = (*ditr)->times.back(); + if (lastDataTime > latestTime) + latestTime = lastDataTime; + } + } + double minDiff = 0.0; + double maxTotal = 0.0; + for (DatasetList::iterator ditr = _datasets.begin(), + de = _datasets.end(); + ditr != de; + ++ditr) + { + GraphDataBase::TimeList& gtimes = (*ditr)->times; + if (gtimes.size() <= 1) + continue; + double totalDiff = 0.0; + for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(), + re = gtimes.rend(); + ritr + 1 != gtimes.rend(); + ritr++) + { + double timeDiff = *ritr - *(ritr + 1); + if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0)) + minDiff = timeDiff; + if (minDiff != 0 + && (totalDiff + timeDiff) / minDiff > linesPossible) + break; + totalDiff += timeDiff; + } + if (totalDiff > maxTotal) + maxTotal = totalDiff; + } + // Now we have a global scale. + _right = latestTime; + if (maxTotal != 0) + _left = latestTime - maxTotal; + else + _left = _right - 1.0; + } + cr->save(); + double horizScale = _zoomFactor * _graphWidth / ( _right - _left); + cr->translate(20.0, 0.0); + cr->set_line_width(_lineWidth); + cr->save(); + cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); + cr->paint(); + cr->restore(); + + for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end(); + itr != e; + ++itr) + { + shared_ptr<GraphDataBase> graphData = *itr; + shared_ptr<GraphData<double> > realData + = dynamic_pointer_cast<GraphData<double> >(*itr); + shared_ptr<GraphData<string> > stringData + = dynamic_pointer_cast<GraphData<string> >(*itr); + cr->save(); + cr->translate(0.0, _graphHeight); + cr->scale(1.0, -1.0); + GraphDataBase::TimeList::iterator lower + = std::lower_bound(graphData->times.begin(), graphData->times.end(), + _left); + GraphDataBase::TimeList::iterator upper + = std::upper_bound(graphData->times.begin(), graphData->times.end(), + _right); + // event bar + if (graphData->style == GraphDataBase::EVENT) + { + double eventHeight = _graphHeight * (graphData->scale / 100.0); + cr->save(); + cr->set_line_width(3 * _lineWidth); + cr->set_source_rgba(graphData->color[0], graphData->color[1], + graphData->color[2], .33); + cr->move_to(0, eventHeight); + cr->line_to(_graphWidth, eventHeight); + cr->stroke(); + cr->restore(); + } + for (GraphDataBase::TimeList::iterator ditr = lower, de = upper; + ditr != de; + ++ditr) + { + size_t dataIndex = ditr - graphData->times.begin(); + cr->set_source_rgba(graphData->color[0], graphData->color[1], + graphData->color[2], 1.0); + if (graphData->style == GraphDataBase::BAR && realData) + { + cr->move_to((*ditr - _left) * horizScale, 0); + cr->line_to((*ditr - _left) * horizScale, + realData->data[dataIndex] * _graphHeight + / graphData->scale); + cr->stroke(); + } + else if (graphData->style == GraphDataBase::DOT && realData) + { + cr->arc((*ditr - _left) * horizScale, + realData->data[dataIndex] * _graphHeight / graphData->scale, + _lineWidth / 2.0, 0.0, M_PI * 2.0); + cr->fill(); + } + else if (graphData->style == GraphDataBase::EVENT && stringData) + { + double eventHeight = _graphHeight * (graphData->scale / 100.0); + cr->save(); + cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, + Cairo::FONT_WEIGHT_NORMAL); + cr->set_font_size(12.0); + cr->save(); + cr->scale(1.0, -1.0); + cr->move_to((*ditr - _left) * horizScale, + -eventHeight -3.0 * _lineWidth - 2.0); + cr->show_text(stringData->data[dataIndex]); + cr->restore(); + cr->rectangle((*ditr - _left) * horizScale - 1.5 * _lineWidth, + eventHeight - 1.5 * _lineWidth, + 3.0 * _lineWidth, 3.0 * _lineWidth); + cr->fill(); + cr->restore(); + } + } + cr->restore(); + cr->save(); + cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, + Cairo::FONT_WEIGHT_BOLD); + cr->set_font_size(14.0); + cr->set_source_rgba(1.0, 1.0, 1.0, .8); + + if (!graphData->title.empty()) + { + cr->move_to(20.0, 20.0); + cr->show_text(graphData->title); + } + if (!graphData->xAxisText.empty()) + { + cr->move_to(10.0, _graphHeight - 5); + cr->show_text(graphData->xAxisText); + } + if (!graphData->yAxisText.empty()) + { + cr->save(); + cr->translate(10.0, _height - 10.0); + cr->rotate(-M_PI / 2.0); + cr->move_to(10.0, 0.0); + cr->show_text(graphData->yAxisText); + cr->restore(); + } + cr->restore(); + + } + cr->restore(); + // Draw axes + double diff = _right - _left; + double majorUnit = pow(10.0, floor(log(diff) / log(10.0))); + double startTime = ceil(_left / majorUnit) * majorUnit; + cr->save(); + cr->set_source_rgba(1.0, 1.0, 1.0, .9); + cr->set_line_cap(Cairo::LINE_CAP_BUTT); + cr->set_line_width(_lineWidth); + cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, + Cairo::FONT_WEIGHT_NORMAL); + cr->set_font_size(10.0); + cr->move_to(20.0, 0.0); + cr->line_to(20.0, _height); + cr->move_to(20.0, _graphHeight); + cr->line_to(_graphWidth, _graphHeight); + cr->stroke(); + std::valarray<double> dash(1); + dash[0] = _graphHeight / 10; + cr->set_dash(dash, 0); + double prevTextAdvance = 0; + for (double tickVal = startTime; tickVal <= _right; tickVal += majorUnit) + { + double x = (tickVal - _left) * horizScale + 20.0; + cr->move_to(x, 0.0); + cr->line_to(x, _graphHeight); + cr->move_to(x, _graphHeight - 5); + std::ostringstream stream; + stream << std::fixed << std::setprecision(0) << tickVal; + Cairo::TextExtents extents; + cr->get_text_extents(stream.str(), extents); + // Room for this label? + if (x + extents.x_bearing > prevTextAdvance) + { + cr->show_text(stream.str()); + prevTextAdvance = x + extents.x_advance; + } + } + cr->stroke(); + cr->restore(); + + if (!_autoScrolling) + { + _playButton->setVisible(true); + _playButton->setOrigin(_graphWidth / 2 - 25, .875 * _graphHeight - 50); + _playButton->draw(cr); + } + + } + + void Graph::addGraphData(std::tr1::shared_ptr<GraphDataBase> data) + { + _datasets.push_back(data); + } + + void Graph::getExtents(double& left, double& right, double& top, + double& bottom) const + { + left = _left; + right = _right; + top = _top; + bottom = _bottom; + } + + void Graph::setExtents(double left, double right, double top, double bottom) + { + _left = left; + _right = right; + _top = top; + _bottom = bottom; + } + + bool Graph::containsPoint(double x, double y) + { + return x >= _x0 && x < _x0 + _width && y >= _y0 && y < _y0 + _height; + } +} diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx new file mode 100644 index 00000000..1cc1892d --- /dev/null +++ b/grapher/Graph.hxx @@ -0,0 +1,48 @@ +#ifndef SYSTEMTAP_GRAPH_HXX +#define SYSTEMTAP_GRAPH_HXX 1 + +#include <cairomm/context.h> + +#include "GraphData.hxx" +#include "CairoWidget.hxx" + +namespace systemtap +{ + class Graph : public CairoWidget + { + public: + friend class GraphWidget; + Graph(); + virtual void draw(Cairo::RefPtr<Cairo::Context> cr); + virtual bool containsPoint(double x, double y); + double getLineWidth() { return _lineWidth; } + void setLineWidth(double lineWidth) { _lineWidth = lineWidth; } + bool getAutoScaling() const { return _autoScaling; } + void setAutoScaling(bool val) { _autoScaling = val; } + void addGraphData(std::tr1::shared_ptr<GraphDataBase> data); + void getExtents(double& left, double& right, double& top, double& bottom) + const; + void setExtents(double left, double right, double top, double bottom); + // extents of the whole graph area + double _width; + double _height; + // Position, extents of the graph + double _graphX; + double _graphY; + double _graphWidth; + double _graphHeight; + double _lineWidth; + bool _autoScaling; + bool _autoScrolling; + double _zoomFactor; + std::tr1::shared_ptr<CairoPlayButton> _playButton; + protected: + typedef std::vector<std::tr1::shared_ptr<GraphDataBase> > DatasetList; + DatasetList _datasets; + double _left; + double _right; + double _top; + double _bottom; + }; +} +#endif diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx index 0f3b0b31..e4c08cfd 100644 --- a/grapher/GraphData.hxx +++ b/grapher/GraphData.hxx @@ -1,44 +1,49 @@ #ifndef SYSTEMTAP_GRAPHDATA_HXX #define SYSTEMTAP_GRAPHDATA_HXX 1 +#include <string> #include <utility> #include <vector> +#include <tr1/memory> namespace systemtap { - struct GraphData + struct GraphDataBase { - public: + virtual ~GraphDataBase() {} enum Style { BAR, - DOT + DOT, + EVENT }; - GraphData() : scale(1.0), style(BAR) + GraphDataBase() : scale(1.0), style(BAR) { color[0] = 0.0; color[1] = 1.0; color[2] = 0.0; } - typedef std::pair<double, double> Datum; - typedef std::vector<Datum> List; + typedef std::vector<double> TimeList; // size of grid square at "normal" viewing double scale; double color[3]; Style style; - List data; - struct Compare - { - bool operator() (const Datum& lhs, const Datum& rhs) const - { - return lhs.first < rhs.first; - } - bool operator() (double lhs, const Datum& rhs) const - { - return lhs < rhs.first; - } - bool operator() (const Datum& lhs, double rhs) const - { - return lhs.first < rhs; - } - }; + std::string title; + std::string xAxisText; + std::string yAxisText; + TimeList times; + }; + + template<typename T> + class GraphData : public GraphDataBase + { + public: + typedef T data_type; + typedef std::vector<data_type> DataList; + DataList data; + }; + struct CSVData + { + typedef std::pair<std::string, std::tr1::shared_ptr<GraphDataBase> > + Element; + std::vector<Element> elements; }; } #endif diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 38f8078d..5b0d1b1c 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -1,18 +1,18 @@ #include <algorithm> #include <ctime> #include <math.h> -#include <sstream> -#include <iomanip> + #include <cairomm/context.h> #include "GraphWidget.hxx" #include "CairoWidget.hxx" namespace systemtap { + using namespace std; + using namespace std::tr1; + GraphWidget::GraphWidget() - : _left(0.0), _right(1.0), _top(1.0), _bottom(0.0), _lineWidth(10), - _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0), - _trackingDrag(false), _playButton(new CairoPlayButton) + : _trackingDrag(false) { add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); @@ -31,33 +31,20 @@ namespace systemtap false); signal_scroll_event() .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false); + // Temporary testing of multiple graphs + shared_ptr<Graph> graph(new Graph); + graph->_graphHeight = 180; + graph->_graphWidth = 580; + _graphs.push_back(graph); } - void GraphWidget::getExtents(double& left, double& right, double& top, - double& bottom) const - { - left = _left; - right = _right; - top = _top; - bottom = _bottom; - } - - void GraphWidget::setExtents(double left, double right, double top, - double bottom) - { - _left = left; - _right = right; - _top = top; - _bottom = bottom; - - } GraphWidget::~GraphWidget() { } - void GraphWidget::addGraphData(std::tr1::shared_ptr<GraphData> data) + void GraphWidget::addGraphData(std::tr1::shared_ptr<GraphDataBase> data) { - _datasets.push_back(data); + _graphs[0]->addGraphData(data); } bool GraphWidget::on_expose_event(GdkEventExpose* event) @@ -75,6 +62,7 @@ namespace systemtap const int height = graphHeight - 20; Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context(); +#if 0 if(event && !_autoScaling) { // clip to the area indicated by the expose event so that we only @@ -83,189 +71,51 @@ namespace systemtap event->area.width, event->area.height); cr->clip(); } - if (_autoScaling) - { - // line separation - int linesPossible = width / ((int)_lineWidth + 2); - // Find latest time. - double latestTime = 0; - for (DatasetList::iterator ditr = _datasets.begin(), - de = _datasets.end(); - ditr != de; - ++ditr) - { - if (!(*ditr)->data.empty()) - { - double lastDataTime = (*ditr)->data.back().first; - if (lastDataTime > latestTime) - latestTime = lastDataTime; - } - } - double minDiff = 0.0; - double maxTotal = 0.0; - for (DatasetList::iterator ditr = _datasets.begin(), - de = _datasets.end(); - ditr != de; - ++ditr) - { - GraphData::List& gdata = (*ditr)->data; - if (gdata.size() <= 1) - continue; - double totalDiff = 0.0; - for (GraphData::List::reverse_iterator ritr = gdata.rbegin(), - re = gdata.rend(); - ritr + 1 != gdata.rend(); - ritr++) - { - double timeDiff = ritr->first - (ritr + 1)->first; - if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0)) - minDiff = timeDiff; - if (minDiff != 0 - && (totalDiff + timeDiff) / minDiff > linesPossible) - break; - totalDiff += timeDiff; - } - if (totalDiff > maxTotal) - maxTotal = totalDiff; - } - // Now we have a global scale. - _right = latestTime; - if (maxTotal != 0) - _left = latestTime - maxTotal; - else - _left = _right - 1.0; - } - cr->save(); - double horizScale = _zoomFactor * width / ( _right - _left); - cr->translate(20.0, 0.0); - cr->set_line_width(_lineWidth); +#endif cr->save(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->paint(); - cr->restore(); - - for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end(); - itr != e; - ++itr) + for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) { cr->save(); - cr->translate(0.0, height); - cr->scale(1.0, -1.0); - GraphData::List::iterator lower - = std::lower_bound((*itr)->data.begin(), (*itr)->data.end(), _left, - GraphData::Compare()); - GraphData::List::iterator upper - = std::upper_bound((*itr)->data.begin(), (*itr)->data.end(), _right, - GraphData::Compare()); - for (GraphData::List::iterator ditr = lower, de = upper; - ditr != de; - ++ditr) - { - cr->set_source_rgba((*itr)->color[0], (*itr)->color[1], - (*itr)->color[2], 1.0); - if ((*itr)->style == GraphData::BAR) - { - cr->move_to((ditr->first - _left) * horizScale, 0); - cr->line_to((ditr->first - _left) * horizScale, - ditr->second * height / (*itr)->scale); - cr->stroke(); - } - else - { - cr->arc((ditr->first - _left) * horizScale, - ditr->second * height / (*itr)->scale, - _lineWidth / 2.0, 0.0, M_PI * 2.0); - cr->fill(); - } - } + cr->translate((*g)->_graphX, (*g)->_graphY); + (*g)->draw(cr); cr->restore(); } - cr->restore(); - cr->save(); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_BOLD); - cr->set_font_size(14.0); - cr->set_source_rgba(1.0, 1.0, 1.0, .8); - - if (!_title.empty()) - { - cr->move_to(20.0, 20.0); - cr->show_text(_title); - } - if (!_xAxisText.empty()) - { - cr->move_to(10.0, graphHeight - 5); - cr->show_text(_xAxisText); - } - if (!_yAxisText.empty()) - { - cr->save(); - cr->translate(10.0, height - 10.0); - cr->rotate(-M_PI / 2.0); - cr->move_to(10.0, 0.0); - cr->show_text(_yAxisText); - cr->restore(); - } - cr->restore(); - // Draw axes - double diff = _right - _left; - double majorUnit = pow(10.0, floor(log(diff) / log(10.0))); - double startTime = floor(_left / majorUnit) * majorUnit; - cr->save(); - cr->set_source_rgba(1.0, 1.0, 1.0, .9); - cr->set_line_cap(Cairo::LINE_CAP_BUTT); - cr->set_line_width(_lineWidth); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_NORMAL); - cr->set_font_size(10.0); - cr->move_to(20.0, 0.0); - cr->line_to(20.0, height); - cr->move_to(20.0, height); - cr->line_to(graphWidth, height); - cr->stroke(); - std::valarray<double> dash(1); - dash[0] = height / 10; - cr->set_dash(dash, 0.0); - for (double tickVal = startTime; tickVal < _right; tickVal += majorUnit) - { - cr->move_to((tickVal - _left) * horizScale + 20.0, graphHeight - 5); - std::ostringstream stream; - stream << std::fixed << std::setprecision(0) << tickVal; - cr->show_text(stream.str()); - cr->move_to((tickVal - _left) * horizScale + 20.0, 0.0); - cr->line_to((tickVal - _left) * horizScale + 20.0, height); - cr->stroke(); - } - cr->stroke(); - cr->restore(); - - if (!_autoScrolling) - { - _playButton->setVisible(true); - _playButton->setOrigin(width / 2 - 25, .875 * height - 50); - _playButton->draw(cr); - } - return true; } bool GraphWidget::on_button_press_event(GdkEventButton* event) { - if (!_autoScrolling && _playButton->containsPoint(event->x, event->y)) + for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) + { + if (event->x >= (*g)->_graphX + && event->x < (*g)->_graphX + (*g)->_graphWidth + && event->y >= (*g)->_graphY + && event->y < (*g)->_graphY + (*g)->_graphHeight) + { + _activeGraph = *g; + break; + } + } + if (!_activeGraph) + return true; + if (!_activeGraph->_autoScrolling + && _activeGraph->_playButton->containsPoint(event->x, event->y)) { - _autoScaling = true; - _autoScrolling = true; + _activeGraph->_autoScaling = true; + _activeGraph->_autoScrolling = true; queue_draw(); } else { _trackingDrag = true; - _autoScaling = false; - _autoScrolling = false; + _activeGraph->_autoScaling = false; + _activeGraph->_autoScrolling = false; _dragOriginX = event->x; _dragOriginY = event->y; - _dragOrigLeft = _left; - _dragOrigRight = _right; + _dragOrigLeft = _activeGraph->_left; + _dragOrigRight = _activeGraph->_right; } return true; } @@ -292,14 +142,14 @@ namespace systemtap x = event->x; y = event->y; } - if (_trackingDrag) + if (_trackingDrag && _activeGraph) { Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); double motion = (x - _dragOriginX) / (double) width; double increment = motion * (_dragOrigLeft - _dragOrigRight); - _left = _dragOrigLeft + increment; - _right = _dragOrigRight + increment; + _activeGraph->_left = _dragOrigLeft + increment; + _activeGraph->_right = _dragOrigRight + increment; queue_draw(); } return true; @@ -307,11 +157,20 @@ namespace systemtap bool GraphWidget::on_scroll_event(GdkEventScroll* event) { - if (event->direction == GDK_SCROLL_UP) - _zoomFactor += .1; - else if (event->direction == GDK_SCROLL_DOWN) - _zoomFactor -= .1; - queue_draw(); + for (GraphList::iterator gitr = _graphs.begin(); + gitr != _graphs.end(); + ++gitr) + { + if ((*gitr)->containsPoint(event->x, event->y)) + { + if (event->direction == GDK_SCROLL_UP) + (*gitr)->_zoomFactor += .1; + else if (event->direction == GDK_SCROLL_DOWN) + (*gitr)->_zoomFactor -= .1; + queue_draw(); + break; + } + } return true; } diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index 46075b78..c15f8fcd 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -6,7 +6,7 @@ #include <tr1/memory> #include <gtkmm/drawingarea.h> -#include "GraphData.hxx" +#include <Graph.hxx> namespace systemtap { @@ -17,20 +17,16 @@ namespace systemtap public: GraphWidget(); virtual ~GraphWidget(); - void addGraphData(std::tr1::shared_ptr<GraphData> data); - void getExtents(double& left, double& right, double& top, double& bottom) const; - void setExtents(double left, double right, double top, double bottom); - double getLineWidth() { return _lineWidth; } - void setLineWidth(double lineWidth) { _lineWidth = lineWidth; } - bool getAutoScaling() const { return _autoScaling; } - void setAutoScaling(bool val) { _autoScaling = val; } - std::string getTitle() const { return _title; } - void setTitle(const std::string& title) { _title = title; } - std::string getXAxisText() const { return _xAxisText; } - void setXAxisText(const std::string& text) { _xAxisText = text; } - std::string getYAxisText() const { return _yAxisText; } - void setYAxisText(const std::string& text) { _yAxisText = text; } + void addGraphData(std::tr1::shared_ptr<GraphDataBase> data); + protected: + typedef std::vector<std::tr1::shared_ptr<Graph> > GraphList; + GraphList _graphs; + // For click and drag + std::tr1::shared_ptr<Graph> _activeGraph; + // Dragging all graphs simultaneously, or perhaps seperately + typedef std::vector<std::pair<double, double> > DragList; + DragList dragCoords; //Override default signal handler: virtual bool on_expose_event(GdkEventExpose* event); virtual bool on_motion_notify_event(GdkEventMotion* event); @@ -38,25 +34,11 @@ namespace systemtap virtual bool on_button_release_event(GdkEventButton* event); virtual bool on_scroll_event(GdkEventScroll* event); bool on_timeout(); - typedef std::vector<std::tr1::shared_ptr<GraphData> > DatasetList; - DatasetList _datasets; - double _left; - double _right; - double _top; - double _bottom; - double _lineWidth; - bool _autoScaling; - bool _autoScrolling; - double _zoomFactor; bool _trackingDrag; double _dragOriginX; double _dragOriginY; double _dragOrigLeft; double _dragOrigRight; - std::string _title; - std::string _xAxisText; - std::string _yAxisText; - std::tr1::shared_ptr<CairoPlayButton> _playButton; }; } #endif // SYSTEMTAP_GRAPHWIDGET_H diff --git a/grapher/Makefile.am b/grapher/Makefile.am index fdb52ef7..0f61d77b 100644 --- a/grapher/Makefile.am +++ b/grapher/Makefile.am @@ -2,6 +2,6 @@ if BUILD_GRAPHER bin_PROGRAMS = grapher grapher_CXXFLAGS = $(GRAPHER_CFLAGS) -grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx +grapher_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx grapher_LDADD = $(GRAPHER_LIBS) endif
\ No newline at end of file diff --git a/grapher/Makefile.in b/grapher/Makefile.in index 88caeda1..227359be 100644 --- a/grapher/Makefile.in +++ b/grapher/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -16,8 +17,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -40,11 +42,14 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" -binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am__grapher_SOURCES_DIST = grapher.cxx GraphWidget.cxx CairoWidget.cxx +am__grapher_SOURCES_DIST = grapher.cxx StapParser.cxx Graph.cxx \ + GraphWidget.cxx CairoWidget.cxx @BUILD_GRAPHER_TRUE@am_grapher_OBJECTS = grapher-grapher.$(OBJEXT) \ +@BUILD_GRAPHER_TRUE@ grapher-StapParser.$(OBJEXT) \ +@BUILD_GRAPHER_TRUE@ grapher-Graph.$(OBJEXT) \ @BUILD_GRAPHER_TRUE@ grapher-GraphWidget.$(OBJEXT) \ @BUILD_GRAPHER_TRUE@ grapher-CairoWidget.$(OBJEXT) grapher_OBJECTS = $(am_grapher_OBJECTS) @@ -55,6 +60,7 @@ grapher_LINK = $(CXXLD) $(grapher_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) @@ -184,7 +190,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @BUILD_GRAPHER_TRUE@grapher_CXXFLAGS = $(GRAPHER_CFLAGS) -@BUILD_GRAPHER_TRUE@grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx +@BUILD_GRAPHER_TRUE@grapher_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx @BUILD_GRAPHER_TRUE@grapher_LDADD = $(GRAPHER_LIBS) all: all-am @@ -199,9 +205,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu grapher/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu grapher/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu grapher/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu grapher/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -219,26 +225,41 @@ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ - else :; fi; \ - done + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) - @list='$(bin_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ - rm -f "$(DESTDIR)$(bindir)/$$f"; \ - done + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) @@ -253,61 +274,91 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-CairoWidget.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-Graph.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-GraphWidget.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-StapParser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-grapher.Po@am__quote@ .cxx.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cxx.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` grapher-grapher.o: grapher.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.o -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx grapher-grapher.obj: grapher.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.obj -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi` -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi` +grapher-StapParser.o: StapParser.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-StapParser.o -MD -MP -MF $(DEPDIR)/grapher-StapParser.Tpo -c -o grapher-StapParser.o `test -f 'StapParser.cxx' || echo '$(srcdir)/'`StapParser.cxx +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-StapParser.Tpo $(DEPDIR)/grapher-StapParser.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='StapParser.cxx' object='grapher-StapParser.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-StapParser.o `test -f 'StapParser.cxx' || echo '$(srcdir)/'`StapParser.cxx + +grapher-StapParser.obj: StapParser.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-StapParser.obj -MD -MP -MF $(DEPDIR)/grapher-StapParser.Tpo -c -o grapher-StapParser.obj `if test -f 'StapParser.cxx'; then $(CYGPATH_W) 'StapParser.cxx'; else $(CYGPATH_W) '$(srcdir)/StapParser.cxx'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-StapParser.Tpo $(DEPDIR)/grapher-StapParser.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='StapParser.cxx' object='grapher-StapParser.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-StapParser.obj `if test -f 'StapParser.cxx'; then $(CYGPATH_W) 'StapParser.cxx'; else $(CYGPATH_W) '$(srcdir)/StapParser.cxx'; fi` + +grapher-Graph.o: Graph.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-Graph.o -MD -MP -MF $(DEPDIR)/grapher-Graph.Tpo -c -o grapher-Graph.o `test -f 'Graph.cxx' || echo '$(srcdir)/'`Graph.cxx +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-Graph.Tpo $(DEPDIR)/grapher-Graph.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Graph.cxx' object='grapher-Graph.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-Graph.o `test -f 'Graph.cxx' || echo '$(srcdir)/'`Graph.cxx + +grapher-Graph.obj: Graph.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-Graph.obj -MD -MP -MF $(DEPDIR)/grapher-Graph.Tpo -c -o grapher-Graph.obj `if test -f 'Graph.cxx'; then $(CYGPATH_W) 'Graph.cxx'; else $(CYGPATH_W) '$(srcdir)/Graph.cxx'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-Graph.Tpo $(DEPDIR)/grapher-Graph.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='Graph.cxx' object='grapher-Graph.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-Graph.obj `if test -f 'Graph.cxx'; then $(CYGPATH_W) 'Graph.cxx'; else $(CYGPATH_W) '$(srcdir)/Graph.cxx'; fi` + grapher-GraphWidget.o: GraphWidget.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.o -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx grapher-GraphWidget.obj: GraphWidget.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.obj -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi` -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi` grapher-CairoWidget.o: CairoWidget.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.o -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx grapher-CairoWidget.obj: CairoWidget.cxx @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.obj -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi` -@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi` @@ -324,7 +375,7 @@ tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -332,29 +383,34 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -375,13 +431,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -412,6 +472,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -432,6 +493,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -440,18 +503,28 @@ install-data-am: install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-binPROGRAMS install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -488,6 +561,7 @@ uninstall-am: uninstall-binPROGRAMS mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-binPROGRAMS + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx new file mode 100644 index 00000000..1c865614 --- /dev/null +++ b/grapher/StapParser.cxx @@ -0,0 +1,204 @@ +#include "StapParser.hxx" + +#include <gtkmm/window.h> +#include <iostream> + +namespace systemtap +{ + using namespace std; + using namespace std::tr1; + +vector<string> commaSplit(const string& inStr, size_t pos = 0) +{ + size_t found = pos; + vector<string> result; + while (1) + { + + size_t commaPos = inStr.find(',', found); + string token + = inStr.substr(found, (commaPos == string::npos + ? string::npos + : commaPos - 1 - found)); + result.push_back(token); + if (commaPos != string::npos) + found = commaPos + 1; + else + break; + } + return result; +} + + void StapParser::parseData(shared_ptr<GraphDataBase> gdata, + double time, const string& dataString) + { + std::istringstream stream(dataString); + shared_ptr<GraphData<double> > dblptr; + shared_ptr<GraphData<string> > strptr; + dblptr = dynamic_pointer_cast<GraphData<double> >(gdata); + if (dblptr) + { + double data; + stream >> data; + dblptr->times.push_back(time); + dblptr->data.push_back(data); + } + else if ((strptr = std::tr1 + ::dynamic_pointer_cast<GraphData<string> >(gdata)) + != 0) + { + strptr->times.push_back(time); + strptr->data.push_back(dataString); + } + } + + size_t findTaggedValue(const string& src, const char* tag, string& result) + { + size_t found; + if ((found = src.find(tag)) != string::npos) + result = src.substr(strlen(tag)); + return found; + } + + bool StapParser::ioCallback(Glib::IOCondition ioCondition) + { + using namespace std; + if ((ioCondition & Glib::IO_IN) == 0) + return true; + char buf[256]; + ssize_t bytes_read = 0; + bytes_read = read(0, buf, sizeof(buf) - 1); + if (bytes_read <= 0) + { + _win.hide(); + return true; + } + buf[bytes_read] = '\0'; + _buffer += buf; + string::size_type ret = string::npos; + while ((ret = _buffer.find('\n')) != string::npos) + { + Glib::ustring dataString(_buffer, 0, ret); + // %DataSet and %CSV declare a data set; all other statements begin with + // the name of a data set. + size_t found; + if (dataString[0] == '%') + { + if ((found = dataString.find("%DataSet:") == 0)) + { + std::string setName; + int hexColor; + double scale; + std::string style; + std::istringstream stream(dataString.substr(9)); + stream >> setName >> scale >> std::hex >> hexColor + >> style; + if (style == "bar" || style == "dot") + { + shared_ptr<GraphData<double> > + dataSet(new GraphData<double>); + if (style == "dot") + dataSet->style = GraphDataBase::DOT; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + _widget.addGraphData(dataSet); + } + else if (style == "discreet") + { + shared_ptr<GraphData<string> > + dataSet(new GraphData<string>); + dataSet->style = GraphDataBase::EVENT; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + _widget.addGraphData(dataSet); + } + } + else if ((found = dataString.find("%CSV:") == 0)) + { + vector<string> tokens = commaSplit(dataString, found + 5); + for (vector<string>::iterator tokIter = tokens.begin(), + e = tokens.end(); + tokIter != e; + ++tokIter) + { + DataMap::iterator setIter = _dataSets.find(*tokIter); + if (setIter != _dataSets.end()) + _csv.elements + .push_back(CSVData::Element(*tokIter, + setIter->second)); + } + } + else + { + cerr << "Unknown declaration " << dataString << endl; + } + } + else + { + std::istringstream stream(dataString); + string setName; + stream >> setName; + DataMap::iterator itr = _dataSets.find(setName); + if (itr != _dataSets.end()) + { + shared_ptr<GraphDataBase> gdata = itr->second; + string decl; + // Hack: scan from the beginning of dataString again + if (findTaggedValue(dataString, "%Title", decl) + != string::npos) + { + gdata->title = decl; + } + else if (findTaggedValue(dataString, "%XAxisTitle:", decl) + != string::npos) + { + gdata->xAxisText = decl; + } + else if (findTaggedValue(dataString, "%YAxisTitle:", decl) + != string::npos) + { + gdata->yAxisText = decl; + } + else if ((found = dataString.find("%YMax:")) != string::npos) + { + double ymax; + std::istringstream stream(dataString.substr(found)); + stream >> ymax; + gdata->scale = ymax; + } + + if (!_csv.elements.empty()) + { + vector<string> tokens = commaSplit(dataString); + int i = 0; + double time; + vector<string>::iterator tokIter = tokens.begin(); + std::istringstream timeStream(*tokIter++); + timeStream >> time; + for (vector<string>::iterator e = tokens.end(); + tokIter != e; + ++tokIter, ++i) + { + parseData(_csv.elements[i].second, time, *tokIter); + } + } + else + { + double time; + string data; + stream >> time >> data; + parseData(itr->second, time, data); + } + } + } + _buffer.erase(0, ret + 1); + } + return true; + } +} diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx new file mode 100644 index 00000000..e11e7302 --- /dev/null +++ b/grapher/StapParser.hxx @@ -0,0 +1,23 @@ +#include "GraphData.hxx" +#include "GraphWidget.hxx" + +#include <string> +namespace systemtap +{ +class StapParser +{ + std::string _buffer; + typedef std::map<std::string, std::tr1::shared_ptr<GraphDataBase> > DataMap; + DataMap _dataSets; + CSVData _csv; + Gtk::Window& _win; + GraphWidget& _widget; +public: + StapParser(Gtk::Window& win, + GraphWidget& widget) : _win(win), _widget(widget) {} + void parseData(std::tr1::shared_ptr<GraphDataBase> gdata, + double time, const std::string& dataString); + bool ioCallback(Glib::IOCondition ioCondition); + +}; +} diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 46182178..a0d35017 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -1,127 +1,135 @@ #include "GraphWidget.hxx" +#include "StapParser.hxx" +#include <cerrno> #include <cmath> +#include <cstdio> +#include <iostream> #include <sstream> #include <string> #include <map> +#include <gtkmm.h> +#include <gtkmm/stock.h> #include <gtkmm/main.h> #include <gtkmm/window.h> #include <unistd.h> #include <poll.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> using namespace systemtap; -class StapParser +class GrapherWindow : public Gtk::Window { - Glib::ustring _buffer; - typedef std::map<std::string, std::tr1::shared_ptr<GraphData> > DataMap; - DataMap _dataSets; - Gtk::Window& _win; - GraphWidget& _widget; public: - StapParser(Gtk::Window& win, - GraphWidget& widget) : _win(win), _widget(widget) {} - - bool ioCallback(Glib::IOCondition ioCondition) - { - if ((ioCondition & Glib::IO_IN) == 0) - return true; - char buf[256]; - ssize_t bytes_read = 0; - bytes_read = read(0, buf, sizeof(buf) - 1); - if (bytes_read <= 0) - { - _win.hide(); - return true; - } - buf[bytes_read] = '\0'; - _buffer += buf; - Glib::ustring::size_type ret = Glib::ustring::npos; - while ((ret = _buffer.find('\n')) != Glib::ustring::npos) - { - Glib::ustring dataString(_buffer, 0, ret); - if (dataString[0] == '%') - { - size_t found; - if ((found = dataString.find("%Title:") == 0)) - { - std::string title = dataString.substr(7); - _widget.setTitle(title); - } - else if ((found = dataString.find("%XAxisTitle:") == 0)) - { - _widget.setXAxisText(dataString.substr(12)); - } - else if ((found = dataString.find("%YAxisTitle:") == 0)) - { - _widget.setYAxisText(dataString.substr(12)); - } - else if ((found = dataString.find("%YMax:") == 0)) - { - double ymax; - std::istringstream stream(dataString.substr(6)); - stream >> ymax; - // _gdata->scale = ymax; - } - else if ((found = dataString.find("%DataSet:") == 0)) - { - std::tr1::shared_ptr<GraphData> dataSet(new GraphData); - std::string setName; - int hexColor; - std::string style; - std::istringstream stream(dataString.substr(9)); - stream >> setName >> dataSet->scale >> std::hex >> hexColor - >> style; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - if (style == "dot") - dataSet->style = GraphData::DOT; - _dataSets.insert(std::make_pair(setName, dataSet)); - _widget.addGraphData(dataSet); - } - } - else - { - std::string dataSet; - double time; - double data; - std::istringstream stream(dataString); - stream >> dataSet >> time >> data; - DataMap::iterator itr = _dataSets.find(dataSet); - if (itr != _dataSets.end()) - itr->second->data.push_back(std::make_pair(time, data)); - } - _buffer.erase(0, ret + 1); - } - return true; - } + GrapherWindow(); + virtual ~GrapherWindow() {} + Gtk::VBox m_Box; + GraphWidget w; +protected: + virtual void on_menu_file_quit(); + // menu support + Glib::RefPtr<Gtk::UIManager> m_refUIManager; + Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup; + }; +GrapherWindow::GrapherWindow() +{ + set_title("systemtap grapher"); + add(m_Box); + + + //Create actions for menus and toolbars: + m_refActionGroup = Gtk::ActionGroup::create(); + //File menu: + m_refActionGroup->add(Gtk::Action::create("FileMenu", "File")); + m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT), + sigc::mem_fun(*this, &GrapherWindow::on_menu_file_quit)); + m_refUIManager = Gtk::UIManager::create(); + m_refUIManager->insert_action_group(m_refActionGroup); + + add_accel_group(m_refUIManager->get_accel_group()); + //Layout the actions in a menubar and toolbar: + Glib::ustring ui_info = + "<ui>" + " <menubar name='MenuBar'>" + " <menu action='FileMenu'>" + " <menuitem action='FileQuit'/>" + " </menu>" + " </menubar>" + "</ui>"; + try + { + m_refUIManager->add_ui_from_string(ui_info); + } + catch(const Glib::Error& ex) + { + std::cerr << "building menus failed: " << ex.what(); + } + Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar"); + if(pMenubar) + m_Box.pack_start(*pMenubar, Gtk::PACK_SHRINK); + m_Box.pack_start(w, Gtk::PACK_EXPAND_WIDGET); + w.show(); + + show_all_children(); + +} +void GrapherWindow::on_menu_file_quit() +{ + hide(); +} + int main(int argc, char** argv) { - Gtk::Main app(argc, argv); + Gtk::Main app(argc, argv); - Gtk::Window win; + GrapherWindow win; - win.set_title("Grapher"); - win.set_default_size(600, 200); + win.set_title("Grapher"); + win.set_default_size(600, 200); - GraphWidget w; - - w.setExtents(0.0, 1.0, 5.0, 0.0); - w.setLineWidth(2); + StapParser stapParser(win, win.w); - StapParser stapParser(win, w); + int childPid = -1; + if (argc > 1) + { + int pipefd[2]; + if (pipe(pipefd) < 0) + { + std::perror("pipe"); + exit(1); + } + if ((childPid = fork()) == -1) + { + exit(1); + } + else if (childPid) + { + dup2(pipefd[0], 0); + close(pipefd[0]); + } + else + { + dup2(pipefd[1], 1); + close(pipefd[1]); + execlp("stap", "stap", argv[1], static_cast<char*>(0)); + exit(1); + return 1; + } + } Glib::signal_io().connect(sigc::mem_fun(stapParser, &StapParser::ioCallback), 0, Glib::IO_IN); - win.add(w); - w.show(); - Gtk::Main::run(win); - + if (childPid > 0) + kill(childPid, SIGTERM); + int status; + while (wait(&status) != -1) + ; return 0; } @@ -1749,6 +1749,19 @@ array_stride (Dwarf_Die *typedie, struct location *origin) dwarf_diename (typedie) ?: "<anonymous>", dwarf_errmsg (-1)); + int typetag = dwarf_tag(&die_mem); + while (typetag == DW_TAG_typedef || + typetag == DW_TAG_const_type || + typetag == DW_TAG_volatile_type) + { + if (dwarf_attr_integrate (&die_mem, DW_AT_type, &attr_mem) == NULL + || dwarf_formref_die (&attr_mem, &die_mem) == NULL) + FAIL (origin, N_("cannot get inner type of type %s: %s"), + dwarf_diename (&die_mem) ?: "<anonymous>", + dwarf_errmsg (-1)); + typetag = dwarf_tag(&die_mem); + } + if (dwarf_attr_integrate (&die_mem, DW_AT_byte_size, &attr_mem) != NULL) { Dwarf_Word stride; @@ -21,6 +21,7 @@ #include "coveragedb.h" #include "git_version.h" #include "rpm_finder.h" +#include "sys/sdt.h" #include <iostream> #include <fstream> @@ -196,16 +197,17 @@ printscript(systemtap_session& s, ostream& o) { o << pp; // Print the locals for -L mode only - if (s.unoptimized) { - for (unsigned j=0; j<p->locals.size(); j++) - { - o << " "; - vardecl* v = p->locals[j]; - v->printsig (o); - } - // Print arguments of probe if there - p->printargs(o); - } + if (s.listing_mode_vars) + { + for (unsigned j=0; j<p->locals.size(); j++) + { + o << " "; + vardecl* v = p->locals[j]; + v->printsig (o); + } + // Print arguments of probe if there + p->printargs(o); + } o << endl; seen.insert (pp); } @@ -464,6 +466,7 @@ main (int argc, char * const argv []) s.unoptimized = false; s.suppress_warnings = false; s.listing_mode = false; + s.listing_mode_vars = false; #ifdef ENABLE_PROLOGUES s.prologue_searching = true; @@ -763,6 +766,7 @@ main (int argc, char * const argv []) break; case 'L': + s.listing_mode_vars = true; s.unoptimized = true; // This causes retention of variables for listing_mode case 'l': @@ -890,6 +894,8 @@ main (int argc, char * const argv []) // PASS 0: setting up s.verbose = s.perpass_verbose[0]; + STAP_PROBE1(stap, pass0__start, &s); + // For PR1477, we used to override $PATH and $LC_ALL and other stuff // here. We seem to use complete pathnames in @@ -941,12 +947,15 @@ main (int argc, char * const argv []) // and reasonably timely exit. setup_signals(&handle_interrupt); + STAP_PROBE1(stap, pass0__end, &s); + struct tms tms_before; times (& tms_before); struct timeval tv_before; gettimeofday (&tv_before, NULL); // PASS 1a: PARSING USER SCRIPT + STAP_PROBE1(stap, pass1a__start, &s); struct stat user_file_stat; int user_file_stat_rc = -1; @@ -998,6 +1007,8 @@ main (int argc, char * const argv []) version_suffixes.push_back (""); // PASS 1b: PARSING LIBRARY SCRIPTS + STAP_PROBE1(stap, pass1b__start, &s); + for (unsigned i=0; i<s.include_path.size(); i++) { // now iterate upon it @@ -1085,6 +1096,8 @@ main (int argc, char * const argv []) << "Try again with another '--vp 1' option." << endl; + STAP_PROBE1(stap, pass1__end, &s); + if (rc || s.last_pass == 1 || pending_interrupts) goto cleanup; times (& tms_before); @@ -1092,6 +1105,7 @@ main (int argc, char * const argv []) // PASS 2: ELABORATION s.verbose = s.perpass_verbose[1]; + STAP_PROBE1(stap, pass2__start, &s); rc = semantic_pass (s); if (s.listing_mode || (rc == 0 && s.last_pass == 2)) @@ -1146,12 +1160,15 @@ main (int argc, char * const argv []) /* Print out list of missing files */ missing_rpm_list_print(s); + STAP_PROBE1(stap, pass2__end, &s); + if (rc || s.listing_mode || s.last_pass == 2 || pending_interrupts) goto cleanup; // PASS 3: TRANSLATION s.verbose = s.perpass_verbose[2]; times (& tms_before); gettimeofday (&tv_before, NULL); + STAP_PROBE1(stap, pass3__start, &s); rc = translate_pass (s); @@ -1175,12 +1192,15 @@ main (int argc, char * const argv []) << "Try again with another '--vp 001' option." << endl; + STAP_PROBE1(stap, pass3__end, &s); + if (rc || s.last_pass == 3 || pending_interrupts) goto cleanup; // PASS 4: COMPILATION s.verbose = s.perpass_verbose[3]; times (& tms_before); gettimeofday (&tv_before, NULL); + STAP_PROBE1(stap, pass4__start, &s); rc = compile_pass (s); if (rc == 0 && s.last_pass == 4) @@ -1245,6 +1265,8 @@ main (int argc, char * const argv []) } } + STAP_PROBE1(stap, pass4__end, &s); + if (rc || s.last_pass == 4 || pending_interrupts) goto cleanup; @@ -1256,6 +1278,7 @@ pass_5: // NB: this message is a judgement call. The other passes don't emit // a "hello, I'm starting" message, but then the others aren't interactive // and don't take an indefinite amount of time. + STAP_PROBE1(stap, pass5__start, &s); if (s.verbose) clog << "Pass 5: starting run." << endl; rc = run_pass (s); times (& tms_after); @@ -1271,9 +1294,13 @@ pass_5: // if (rc) goto cleanup; + STAP_PROBE1(stap, pass5__end, &s); + // PASS 6: cleaning up cleanup: + STAP_PROBE1(stap, pass6__start, &s); + // update the database information if (!rc && s.tapset_compile_coverage && !pending_interrupts) { #ifdef HAVE_LIBSQLITE3 @@ -1305,6 +1332,8 @@ pass_5: } } + STAP_PROBE1(stap, pass6__end, &s); + return (rc||pending_interrupts) ? EXIT_FAILURE : EXIT_SUCCESS; } @@ -2346,27 +2346,8 @@ parser::parse_symbol () expect_unknown(tok_string, cop->module); } expect_op(")"); - while (true) - { - string c; - if (peek_op ("->")) - { - next(); - expect_ident_or_keyword (c); - cop->components.push_back - (make_pair (target_symbol::comp_struct_member, c)); - } - else if (peek_op ("[")) - { - next(); - expect_unknown (tok_number, c); - expect_op ("]"); - cop->components.push_back - (make_pair (target_symbol::comp_literal_array_index, c)); - } - else - break; - } + parse_target_symbol_components(cop); + // if there aren't any dereferences, then the cast is pointless if (cop->components.empty()) { @@ -2494,27 +2475,7 @@ parser::parse_symbol () target_symbol *tsym = new target_symbol; tsym->tok = t; tsym->base_name = name; - while (true) - { - string c; - if (peek_op ("->")) - { - next(); - expect_ident_or_keyword (c); - tsym->components.push_back - (make_pair (target_symbol::comp_struct_member, c)); - } - else if (peek_op ("[")) - { - next(); - expect_unknown (tok_number, c); - expect_op ("]"); - tsym->components.push_back - (make_pair (target_symbol::comp_literal_array_index, c)); - } - else - break; - } + parse_target_symbol_components(tsym); return tsym; } @@ -2604,4 +2565,33 @@ parser::parse_symbol () return sym; } + +void +parser::parse_target_symbol_components (target_symbol* e) +{ + while (true) + { + if (peek_op ("->")) + { + const token* t = next(); + string member; + expect_ident_or_keyword (member); + e->components.push_back (target_symbol::component(t, member)); + } + else if (peek_op ("[")) + { + const token* t = next(); + expression* index = parse_expression(); + literal_number* ln = dynamic_cast<literal_number*>(index); + if (ln) + e->components.push_back (target_symbol::component(t, ln->value)); + else + e->components.push_back (target_symbol::component(t, index)); + expect_op ("]"); + } + else + break; + } +} + /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ @@ -112,6 +112,7 @@ struct next_statement; struct continue_statement; struct indexable; struct expression; +struct target_symbol; struct hist_op; class parser @@ -203,6 +204,8 @@ private: // nonterminals expression* parse_crement (); expression* parse_value (); expression* parse_symbol (); + + void parse_target_symbol_components (target_symbol* e); }; diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c index 010cab12..6a2ac77e 100644 --- a/runtime/staprun/common.c +++ b/runtime/staprun/common.c @@ -451,6 +451,7 @@ int send_request(int type, void *data, int len) char buf[1024]; int rc = 0; + STAP_PROBE3(stapio, send__ctlmsg, type, data, len); /* Before doing memcpy, make sure 'buf' is big enough. */ if ((len + 4) > (int)sizeof(buf)) { _err("exceeded maximum send_request size.\n"); diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 7125a7bb..45b142bc 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -485,6 +485,7 @@ int stp_main_loop(void) type = *(uint32_t *) recvbuf; data = (void *)(recvbuf + sizeof(uint32_t)); nb -= sizeof(uint32_t); + STAP_PROBE3(staprun, recv__ctlmsg, type, data, nb); switch (type) { #if STP_TRANSPORT_VERSION == 1 diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 917990dc..554eecc8 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -202,6 +202,7 @@ static int remove_module(const char *name, int verb) close_ctl_channel(); dbug(2, "removing module %s\n", name); + STAP_PROBE1(staprun, remove__module, name); ret = delete_module (name, 0); if (ret != 0) { err("Error removing module '%s': %s.\n", name, strerror(errno)); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 6af04042..0a1ca885 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -38,6 +38,9 @@ /* Include config.h to pick up dependency for --prefix usage. */ #include "config.h" +/* For STAP_PROBE in staprun.c, staprun_funcs.c, mainloop.c and common.c */ +#include "sys/sdt.h" + extern void eprintf(const char *fmt, ...); extern void switch_syslog(const char *name); diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index 669dc996..ed7f4fc3 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -94,6 +94,7 @@ int insert_module(const char *path, const char *special_options, char **options) return -1; } + STAP_PROBE1(staprun, insert__module, path); /* Actually insert the module */ ret = init_module(file, sbuf.st_size, opts); saved_errno = errno; diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c index 3af1bf7d..39b79e10 100644 --- a/runtime/transport/ring_buffer.c +++ b/runtime/transport/ring_buffer.c @@ -18,12 +18,14 @@ struct _stp_data_entry { * Trace iterator - used by printout routines who present trace * results to users and which routines might sleep, etc: */ -struct _stp_ring_buffer_data { +struct _stp_iterator { #if 0 struct trace_array *tr; struct tracer *trace; void *private; +#endif int cpu_file; +#if 0 struct mutex mutex; #endif struct ring_buffer_iter *buffer_iter[NR_CPUS]; @@ -44,10 +46,19 @@ struct _stp_ring_buffer_data { #endif }; +/* In bulk mode, we need 1 'struct _stp_iterator' for each cpu. In + * 'normal' mode, we only need 1 'struct _stp_iterator' (since all + * output is sent through 1 file). */ +#ifdef STP_BULKMODE +#define NR_ITERS NR_CPUS +#else +#define NR_ITERS 1 +#endif + struct _stp_relay_data_type { enum _stp_transport_state transport_state; struct ring_buffer *rb; - struct _stp_ring_buffer_data rb_data; + struct _stp_iterator iter[NR_ITERS]; cpumask_var_t trace_reader_cpumask; struct timer_list timer; int overwrite_flag; @@ -99,7 +110,10 @@ fail: static int _stp_data_open_trace(struct inode *inode, struct file *file) { - int cpu_file = (int)(long) inode->i_private; + struct _stp_iterator *iter = inode->i_private; +#ifdef STP_BULKMODE + int cpu_file = iter->cpu_file; +#endif /* We only allow for one reader per cpu */ dbug_trans(1, "trace attach\n"); @@ -123,10 +137,11 @@ static int _stp_data_open_trace(struct inode *inode, struct file *file) static int _stp_data_release_trace(struct inode *inode, struct file *file) { - int cpu_file = (int)(long) inode->i_private; + struct _stp_iterator *iter = inode->i_private; + dbug_trans(1, "trace detach\n"); #ifdef STP_BULKMODE - cpumask_clear_cpu(cpu_file, _stp_relay_data.trace_reader_cpumask); + cpumask_clear_cpu(iter->cpu_file, _stp_relay_data.trace_reader_cpumask); #else cpumask_clear(_stp_relay_data.trace_reader_cpumask); #endif @@ -176,10 +191,14 @@ _stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf, return cnt; } -static int _stp_ring_buffer_empty_cpu(int cpu) +static int _stp_ring_buffer_empty_cpu(struct _stp_iterator *iter) { - if (_stp_relay_data.rb_data.buffer_iter[cpu]) { - if (ring_buffer_iter_empty(_stp_relay_data.rb_data.buffer_iter[cpu])) + int cpu; + +#ifdef STP_BULKMODE + cpu = iter->cpu_file; + if (iter->buffer_iter[cpu]) { + if (ring_buffer_iter_empty(iter->buffer_iter[cpu])) return 1; } else { @@ -187,39 +206,56 @@ static int _stp_ring_buffer_empty_cpu(int cpu) return 1; } return 0; +#else + for_each_possible_cpu(cpu) { + if (iter->buffer_iter[cpu]) { + if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) + return 0; + } + else { + if (!ring_buffer_empty_cpu(_stp_relay_data.rb, cpu)) + return 0; + } + } + return 1; +#endif } static int _stp_ring_buffer_empty(void) { + struct _stp_iterator *iter; #ifdef STP_BULKMODE - return _stp_ring_buffer_empty_cpu(_stp_relay_data.rb_data.cpu); -#else int cpu; + for_each_possible_cpu(cpu) { - if (! _stp_ring_buffer_empty_cpu(cpu)) + iter = &_stp_relay_data.iter[cpu]; + if (! _stp_ring_buffer_empty_cpu(iter)) return 0; } return 1; +#else + iter = &_stp_relay_data.iter[0]; + return _stp_ring_buffer_empty_cpu(iter); #endif } -static void _stp_ring_buffer_iterator_increment(void) +static void _stp_ring_buffer_iterator_increment(struct _stp_iterator *iter) { - if (_stp_relay_data.rb_data.buffer_iter[_stp_relay_data.rb_data.cpu]) { - ring_buffer_read(_stp_relay_data.rb_data.buffer_iter[_stp_relay_data.rb_data.cpu], NULL); - } + if (iter->buffer_iter[iter->cpu]) + ring_buffer_read(iter->buffer_iter[iter->cpu], NULL); } -static void _stp_ring_buffer_consume(void) +static void _stp_ring_buffer_consume(struct _stp_iterator *iter) { - _stp_ring_buffer_iterator_increment(); - ring_buffer_consume(_stp_relay_data.rb, _stp_relay_data.rb_data.cpu, - &_stp_relay_data.rb_data.ts); + _stp_ring_buffer_iterator_increment(iter); + ring_buffer_consume(_stp_relay_data.rb, iter->cpu, &iter->ts); } static ssize_t _stp_tracing_wait_pipe(struct file *filp) { - if (_stp_ring_buffer_empty()) { + struct _stp_iterator *iter = filp->private_data; + + if (_stp_ring_buffer_empty_cpu(iter)) { if ((filp->f_flags & O_NONBLOCK)) { dbug_trans(1, "returning -EAGAIN\n"); return -EAGAIN; @@ -237,33 +273,32 @@ static ssize_t _stp_tracing_wait_pipe(struct file *filp) return 1; } -static struct ring_buffer_event *_stp_peek_next_event(int cpu, u64 *ts) +static struct ring_buffer_event * +_stp_peek_next_event(struct _stp_iterator *iter, int cpu, u64 *ts) { - if (_stp_relay_data.rb_data.buffer_iter[cpu]) - return ring_buffer_iter_peek(_stp_relay_data.rb_data.buffer_iter[cpu], ts); + if (iter->buffer_iter[cpu]) + return ring_buffer_iter_peek(iter->buffer_iter[cpu], ts); else return ring_buffer_peek(_stp_relay_data.rb, cpu, ts); } /* Find the next real event */ -static struct ring_buffer_event *_stp_find_next_event(int cpu_file) +static struct ring_buffer_event * +_stp_find_next_event(struct _stp_iterator *iter) { struct ring_buffer_event *event; + int cpu_file = iter->cpu_file; #ifdef STP_BULKMODE /* * If we are in a per_cpu trace file, don't bother by iterating over * all cpus and peek directly. */ - if (_stp_ring_buffer_empty_cpu(cpu_file)) + if (ring_buffer_iter_empty(iter->buffer_iter[cpu_file])) return NULL; - event = _stp_peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts); - _stp_relay_data.rb_data.cpu = cpu_file; + event = _stp_peek_next_event(iter, cpu_file, &iter->ts); + iter->cpu = cpu_file; -#if 0 - if (event) - _stp_ring_buffer_iterator_increment(); -#endif return event; #else struct ring_buffer_event *next = NULL; @@ -272,10 +307,13 @@ static struct ring_buffer_event *_stp_find_next_event(int cpu_file) int cpu; for_each_possible_cpu(cpu) { - if (_stp_ring_buffer_empty_cpu(cpu)) + if (iter->buffer_iter[cpu] == NULL) + continue; + + if (ring_buffer_iter_empty(iter->buffer_iter[cpu])) continue; - event = _stp_peek_next_event(cpu, &ts); + event = _stp_peek_next_event(iter, cpu, &ts); /* * Pick the event with the smallest timestamp: @@ -287,12 +325,8 @@ static struct ring_buffer_event *_stp_find_next_event(int cpu_file) } } - _stp_relay_data.rb_data.cpu = next_cpu; - _stp_relay_data.rb_data.ts = next_ts; -#if 0 - if (next) - _stp_ring_buffer_iterator_increment(); -#endif + iter->cpu = next_cpu; + iter->ts = next_ts; return next; #endif } @@ -307,8 +341,10 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, { ssize_t sret; struct ring_buffer_event *event; - int cpu_file = (int)(long) filp->private_data; -#ifndef STP_BULKMODE + struct _stp_iterator *iter = filp->private_data; +#ifdef STP_BULKMODE + int cpu_file = iter->cpu_file; +#else int cpu; #endif @@ -320,36 +356,34 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, goto out; #ifdef STP_BULKMODE - _stp_relay_data.rb_data.buffer_iter[cpu_file] + iter->buffer_iter[cpu_file] = ring_buffer_read_start(_stp_relay_data.rb, cpu_file); + if (iter->buffer_iter[cpu_file] == NULL) { + dbug_trans(0, "buffer_iter[%d] was NULL\n", cpu_file); + goto out; + } #else for_each_possible_cpu(cpu) { - _stp_relay_data.rb_data.buffer_iter[cpu] + iter->buffer_iter[cpu] = ring_buffer_read_start(_stp_relay_data.rb, cpu); } #endif - _stp_relay_data.rb_data.ts = 0; + iter->ts = 0; dbug_trans(0, "iterator(s) started\n"); - /* stop when tracing is finished */ - if (_stp_ring_buffer_empty()) { - sret = 0; - goto out; - } - if (cnt >= PAGE_SIZE) cnt = PAGE_SIZE - 1; dbug_trans(1, "sret = %lu\n", (unsigned long)sret); sret = 0; - while ((event = _stp_find_next_event(cpu_file)) != NULL) { + while ((event = _stp_find_next_event(iter)) != NULL) { ssize_t len; len = _stp_event_to_user(event, ubuf, cnt); if (len <= 0) break; - _stp_ring_buffer_consume(); + _stp_ring_buffer_consume(iter); dbug_trans(1, "event consumed\n"); ubuf += len; cnt -= len; @@ -360,16 +394,16 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf, out: #ifdef STP_BULKMODE - if (_stp_relay_data.rb_data.buffer_iter[cpu_file]) { - ring_buffer_read_finish(_stp_relay_data.rb_data.buffer_iter[cpu_file]); - _stp_relay_data.rb_data.buffer_iter[cpu_file] = NULL; + if (iter->buffer_iter[cpu_file]) { + ring_buffer_read_finish(iter->buffer_iter[cpu_file]); + iter->buffer_iter[cpu_file] = NULL; dbug_trans(0, "iterator finished\n"); } #else for_each_possible_cpu(cpu) { - if (_stp_relay_data.rb_data.buffer_iter[cpu]) { - ring_buffer_read_finish(_stp_relay_data.rb_data.buffer_iter[cpu]); - _stp_relay_data.rb_data.buffer_iter[cpu] = NULL; + if (iter->buffer_iter[cpu]) { + ring_buffer_read_finish(iter->buffer_iter[cpu]); + iter->buffer_iter[cpu] = NULL; } } dbug_trans(0, "iterator(s) finished\n"); @@ -381,11 +415,13 @@ out: static unsigned int _stp_data_poll_trace(struct file *filp, poll_table *poll_table) { + struct _stp_iterator *iter = filp->private_data; + dbug_trans(1, "entry\n"); - if (! _stp_ring_buffer_empty()) + if (! _stp_ring_buffer_empty_cpu(iter)) return POLLIN | POLLRDNORM; poll_wait(filp, &_stp_poll_wait, poll_table); - if (! _stp_ring_buffer_empty()) + if (! _stp_ring_buffer_empty_cpu(iter)) return POLLIN | POLLRDNORM; dbug_trans(1, "exit\n"); @@ -446,6 +482,7 @@ _stp_data_write_reserve(size_t size_request, void **entry) #endif if (unlikely(! event)) { int cpu; + struct _stp_iterator *iter; dbug_trans(0, "event = NULL (%p)?\n", event); if (! _stp_relay_data.overwrite_flag) { @@ -457,15 +494,20 @@ _stp_data_write_reserve(size_t size_request, void **entry) * full, take a event out of the buffer and consume it * (throw it away). This should make room for the new * data. */ +#ifdef STP_BULKMODE cpu = raw_smp_processor_id(); - event = _stp_find_next_event(cpu); + iter = &_stp_relay_data.iter[cpu]; +#else + iter = &_stp_relay_data.iter[0]; +#endif + event = _stp_find_next_event(iter); if (event) { ssize_t len; sde = (struct _stp_data_entry *)ring_buffer_event_data(event); if (sde->len < size_request) size_request = sde->len; - _stp_ring_buffer_consume(); + _stp_ring_buffer_consume(iter); /* Try to reserve again. */ #ifdef STAPCONF_RING_BUFFER_FLAGS @@ -595,14 +637,20 @@ static int _stp_transport_data_fs_init(void) __stp_entry[cpu]->d_inode->i_uid = _stp_uid; __stp_entry[cpu]->d_inode->i_gid = _stp_gid; - __stp_entry[cpu]->d_inode->i_private = (void *)(long)cpu; + __stp_entry[cpu]->d_inode->i_private = &_stp_relay_data.iter[cpu]; #ifndef STP_BULKMODE - if (cpu != 0) - break; + break; #endif } +#ifdef STP_BULKMODE + for_each_possible_cpu(cpu) { + _stp_relay_data.iter[cpu].cpu_file = cpu; + _stp_relay_data.iter[cpu].cpu = cpu; + } +#endif + dbug_trans(1, "returning 0...\n"); _stp_relay_data.transport_state = STP_TRANSPORT_INITIALIZED; return 0; diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h index 9f488f07..b19df584 100644 --- a/runtime/unwind/i386.h +++ b/runtime/unwind/i386.h @@ -92,7 +92,7 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, #endif } - info->call_frame = 1; + info->call_frame = 0; } static inline void arch_unw_init_blocked(struct unwind_frame_info *info) diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h index 3c70f206..8860b8ee 100644 --- a/runtime/unwind/x86_64.h +++ b/runtime/unwind/x86_64.h @@ -107,7 +107,7 @@ static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs) { info->regs = *regs; - info->call_frame = 1; + info->call_frame = 0; } static inline void arch_unw_init_blocked(struct unwind_frame_info *info) @@ -103,6 +103,7 @@ struct systemtap_session bool keep_tmpdir; bool guru_mode; bool listing_mode; + bool listing_mode_vars; bool bulk_mode; bool unoptimized; bool merge; @@ -132,7 +132,7 @@ debugging information for $target variables. Unoptimized mode. Disable unused code elision during elaboration. .TP .B \-w -Suppressed warnings mode. Disable warning messages for elided code in user script. +Suppressed warnings mode. Disables all warning messages. .TP .BI \-b Use bulk mode (percpu files) for kernel-to-user data transfer. diff --git a/staptree.cxx b/staptree.cxx index a762cf47..aa37b754 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -187,6 +187,31 @@ operator << (ostream& o, const exp_type& e) } +void +target_symbol::assert_no_components(const std::string& tapset) +{ + if (components.empty()) + return; + + switch (components[0].type) + { + case target_symbol::comp_literal_array_index: + case target_symbol::comp_expression_array_index: + throw semantic_error(tapset + " variable '" + base_name + + "' may not be used as array", + components[0].tok); + case target_symbol::comp_struct_member: + throw semantic_error(tapset + " variable '" + base_name + + "' may not be used as a structure", + components[0].tok); + default: + throw semantic_error ("invalid use of " + tapset + + " variable '" + base_name + "'", + components[0].tok); + } +} + + // ------------------------------------------------------------------------ // parse tree printing @@ -260,27 +285,41 @@ void symbol::print (ostream& o) const } -void target_symbol::print (std::ostream& o) const +void target_symbol::component::print (ostream& o) const +{ + switch (type) + { + case comp_struct_member: + o << "->" << member; + break; + case comp_literal_array_index: + o << '[' << num_index << ']'; + break; + case comp_expression_array_index: + o << '[' << *expr_index << ']'; + break; + } +} + + +std::ostream& operator << (std::ostream& o, const target_symbol::component& c) +{ + c.print (o); + return o; +} + + +void target_symbol::print (ostream& o) const { if (addressof) o << "&"; o << base_name; for (unsigned i = 0; i < components.size(); ++i) - { - switch (components[i].first) - { - case comp_literal_array_index: - o << '[' << components[i].second << ']'; - break; - case comp_struct_member: - o << "->" << components[i].second; - break; - } - } + o << components[i]; } -void cast_op::print (std::ostream& o) const +void cast_op::print (ostream& o) const { if (addressof) o << "&"; @@ -290,17 +329,7 @@ void cast_op::print (std::ostream& o) const o << ", " << lex_cast_qstring (module); o << ')'; for (unsigned i = 0; i < components.size(); ++i) - { - switch (components[i].first) - { - case comp_literal_array_index: - o << '[' << components[i].second << ']'; - break; - case comp_struct_member: - o << "->" << components[i].second; - break; - } - } + o << components[i]; } @@ -1247,6 +1276,22 @@ target_symbol::visit (visitor* u) } void +target_symbol::visit_components (visitor* u) +{ + for (unsigned i = 0; i < components.size(); ++i) + if (components[i].type == comp_expression_array_index) + components[i].expr_index->visit (u); +} + +void +target_symbol::visit_components (update_visitor* u) +{ + for (unsigned i = 0; i < components.size(); ++i) + if (components[i].type == comp_expression_array_index) + u->replace (components[i].expr_index); +} + +void cast_op::visit (visitor* u) { u->visit_cast_op(this); @@ -1614,14 +1659,16 @@ traversing_visitor::visit_symbol (symbol*) } void -traversing_visitor::visit_target_symbol (target_symbol*) +traversing_visitor::visit_target_symbol (target_symbol* e) { + e->visit_components (this); } void traversing_visitor::visit_cast_op (cast_op* e) { e->operand->visit (this); + e->visit_components (this); } void @@ -1723,6 +1770,8 @@ varuse_collecting_visitor::visit_target_symbol (target_symbol *e) if (is_active_lvalue (e)) embedded_seen = true; + + functioncall_traversing_visitor::visit_target_symbol (e); } void @@ -2164,7 +2213,7 @@ void update_visitor::visit_block (block* s) { for (unsigned i = 0; i < s->statements.size(); ++i) - s->statements[i] = require (s->statements[i]); + replace (s->statements[i]); provide (s); } @@ -2183,26 +2232,26 @@ update_visitor::visit_null_statement (null_statement* s) void update_visitor::visit_expr_statement (expr_statement* s) { - s->value = require (s->value); + replace (s->value); provide (s); } void update_visitor::visit_if_statement (if_statement* s) { - s->condition = require (s->condition); - s->thenblock = require (s->thenblock); - s->elseblock = require (s->elseblock); + replace (s->condition); + replace (s->thenblock); + replace (s->elseblock); provide (s); } void update_visitor::visit_for_loop (for_loop* s) { - s->init = require (s->init); - s->cond = require (s->cond); - s->incr = require (s->incr); - s->block = require (s->block); + replace (s->init); + replace (s->cond); + replace (s->incr); + replace (s->block); provide (s); } @@ -2210,24 +2259,24 @@ void update_visitor::visit_foreach_loop (foreach_loop* s) { for (unsigned i = 0; i < s->indexes.size(); ++i) - s->indexes[i] = require (s->indexes[i]); - s->base = require (s->base); - s->limit = require (s->limit); - s->block = require (s->block); + replace (s->indexes[i]); + replace (s->base); + replace (s->limit); + replace (s->block); provide (s); } void update_visitor::visit_return_statement (return_statement* s) { - s->value = require (s->value); + replace (s->value); provide (s); } void update_visitor::visit_delete_statement (delete_statement* s) { - s->value = require (s->value); + replace (s->value); provide (s); } @@ -2264,29 +2313,29 @@ update_visitor::visit_literal_number (literal_number* e) void update_visitor::visit_binary_expression (binary_expression* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } void update_visitor::visit_unary_expression (unary_expression* e) { - e->operand = require (e->operand); + replace (e->operand); provide (e); } void update_visitor::visit_pre_crement (pre_crement* e) { - e->operand = require (e->operand); + replace (e->operand); provide (e); } void update_visitor::visit_post_crement (post_crement* e) { - e->operand = require (e->operand); + replace (e->operand); provide (e); } @@ -2294,56 +2343,56 @@ update_visitor::visit_post_crement (post_crement* e) void update_visitor::visit_logical_or_expr (logical_or_expr* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } void update_visitor::visit_logical_and_expr (logical_and_expr* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } void update_visitor::visit_array_in (array_in* e) { - e->operand = require (e->operand); + replace (e->operand); provide (e); } void update_visitor::visit_comparison (comparison* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } void update_visitor::visit_concatenation (concatenation* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } void update_visitor::visit_ternary_expression (ternary_expression* e) { - e->cond = require (e->cond); - e->truevalue = require (e->truevalue); - e->falsevalue = require (e->falsevalue); + replace (e->cond); + replace (e->truevalue); + replace (e->falsevalue); provide (e); } void update_visitor::visit_assignment (assignment* e) { - e->left = require (e->left); - e->right = require (e->right); + replace (e->left); + replace (e->right); provide (e); } @@ -2356,22 +2405,24 @@ update_visitor::visit_symbol (symbol* e) void update_visitor::visit_target_symbol (target_symbol* e) { + e->visit_components (this); provide (e); } void update_visitor::visit_cast_op (cast_op* e) { - e->operand = require (e->operand); + replace (e->operand); + e->visit_components (this); provide (e); } void update_visitor::visit_arrayindex (arrayindex* e) { - e->base = require (e->base); + replace (e->base); for (unsigned i = 0; i < e->indexes.size(); ++i) - e->indexes[i] = require (e->indexes[i]); + replace (e->indexes[i]); provide (e); } @@ -2379,7 +2430,7 @@ void update_visitor::visit_functioncall (functioncall* e) { for (unsigned i = 0; i < e->args.size(); ++i) - e->args[i] = require (e->args[i]); + replace (e->args[i]); provide (e); } @@ -2387,27 +2438,27 @@ void update_visitor::visit_print_format (print_format* e) { for (unsigned i = 0; i < e->args.size(); ++i) - e->args[i] = require (e->args[i]); - e->hist = require (e->hist); + replace (e->args[i]); + replace (e->hist); provide (e); } void update_visitor::visit_stat_op (stat_op* e) { - e->stat = require (e->stat); + replace (e->stat); provide (e); } void update_visitor::visit_hist_op (hist_op* e) { - e->stat = require (e->stat); + replace (e->stat); provide (e); } template <> indexable* -update_visitor::require <indexable*> (indexable* src, bool clearok) +update_visitor::require <indexable> (indexable* src, bool clearok) { indexable *dst = NULL; if (src != NULL) @@ -60,6 +60,7 @@ std::ostream& operator << (std::ostream& o, const exp_type& e); struct token; struct visitor; +struct update_visitor; struct expression { @@ -229,18 +230,42 @@ struct target_symbol: public symbol enum component_type { comp_struct_member, - comp_literal_array_index + comp_literal_array_index, + comp_expression_array_index, }; + + struct component + { + const token* tok; + component_type type; + std::string member; // comp_struct_member + int64_t num_index; // comp_literal_array_index + expression* expr_index; // comp_expression_array_index + + component(const token* t, const std::string& m): + tok(t), type(comp_struct_member), member(m) {} + component(const token* t, int64_t n): + tok(t), type(comp_literal_array_index), num_index(n) {} + component(const token* t, expression* e): + tok(t), type(comp_expression_array_index), expr_index(e) {} + void print (std::ostream& o) const; + }; + bool addressof; std::string base_name; - std::vector<std::pair<component_type, std::string> > components; + std::vector<component> components; std::string probe_context_var; semantic_error* saved_conversion_error; target_symbol(): addressof(false), saved_conversion_error (0) {} void print (std::ostream& o) const; void visit (visitor* u); + void visit_components (visitor* u); + void visit_components (update_visitor* u); + void assert_no_components(const std::string& tapset); }; +std::ostream& operator << (std::ostream& o, const target_symbol::component& c); + struct cast_op: public target_symbol { @@ -834,25 +859,30 @@ struct throwing_visitor: public visitor struct update_visitor: public visitor { - template <typename T> T require (T src, bool clearok=false) + template <typename T> T* require (T* src, bool clearok=false) { - T dst = NULL; + T* dst = NULL; if (src != NULL) { src->visit(this); assert(!targets.empty()); - dst = static_cast<T>(targets.top()); + dst = static_cast<T*>(targets.top()); targets.pop(); assert(clearok || dst); } return dst; } - template <typename T> void provide (T src) + template <typename T> void provide (T* src) { targets.push(static_cast<void*>(src)); } + template <typename T> void replace (T*& src, bool clearok=false) + { + src = require(src, clearok); + } + virtual ~update_visitor() { assert(targets.empty()); } virtual void visit_block (block *s); @@ -894,7 +924,7 @@ private: }; template <> indexable* -update_visitor::require <indexable*> (indexable* src, bool clearok); +update_visitor::require <indexable> (indexable* src, bool clearok); // A visitor which performs a deep copy of the root node it's applied // to. NB: It does not copy any of the variable or function @@ -904,7 +934,7 @@ update_visitor::require <indexable*> (indexable* src, bool clearok); struct deep_copy_visitor: public update_visitor { - template <typename T> static T deep_copy (T e) + template <typename T> static T* deep_copy (T* e) { deep_copy_visitor v; return v.require (e); diff --git a/tapset-mark.cxx b/tapset-mark.cxx index a358a20e..6b4f47c5 100644 --- a/tapset-mark.cxx +++ b/tapset-mark.cxx @@ -103,23 +103,7 @@ mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) if (is_active_lvalue (e)) throw semantic_error("write to marker parameter not permitted", e->tok); - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("marker argument may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("marker argument may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid marker argument use", e->tok); - break; - } - } + e->assert_no_components("marker"); // Remember that we've seen a target variable. target_symbol_seen = true; @@ -138,23 +122,7 @@ mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) if (is_active_lvalue (e)) throw semantic_error("write to marker '" + sname + "' not permitted", e->tok); - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("marker '" + sname + "' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("marker '" + sname + "' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid marker '" + sname + "' use", e->tok); - break; - } - } + e->assert_no_components("marker"); if (e->base_name == "$format" || e->base_name == "$name") { string fname; @@ -255,7 +223,7 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s, // Now expand the local variables in the probe body mark_var_expanding_visitor v (sess, name, mark_args); - this->body = v.require (this->body); + v.replace (this->body); target_symbol_seen = v.target_symbol_seen; if (sess.verbose > 2) diff --git a/tapset-perfmon.cxx b/tapset-perfmon.cxx index 0fb567f7..86806d61 100644 --- a/tapset-perfmon.cxx +++ b/tapset-perfmon.cxx @@ -67,24 +67,7 @@ perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e) if (e->addressof) throw semantic_error("cannot take address of perfmon variable", e->tok); - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("perfmon probe '$counter' variable may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("perfmon probe '$counter' variable may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of perfmon probe '$counter' variable", - e->tok); - break; - } - } + e->assert_no_components("perfmon"); ec->code = "THIS->__retvalue = _pfm_pmd_x[" + lex_cast<string>(counter_number) + "].reg_num;"; @@ -170,7 +153,7 @@ perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l, // Now expand the local variables in the probe body perfmon_var_expanding_visitor v (sess, probes_allocated-1); - this->body = v.require (this->body); + v.replace (this->body); if (sess.verbose > 1) clog << "perfmon-based probe" << endl; diff --git a/tapset-procfs.cxx b/tapset-procfs.cxx index a996ee32..527b4486 100644 --- a/tapset-procfs.cxx +++ b/tapset-procfs.cxx @@ -94,7 +94,7 @@ procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p, { // Expand local variables in the probe body procfs_var_expanding_visitor v (s, name, path, write); - this->body = v.require (this->body); + v.replace (this->body); target_symbol_seen = v.target_symbol_seen; } @@ -358,24 +358,7 @@ procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e) throw semantic_error ("invalid target symbol for procfs probe, $value expected", e->tok); - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("procfs target variable '$value' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("procfs target variable '$value' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of procfs target variable '$value'", - e->tok); - break; - } - } + e->assert_no_components("procfs"); bool lvalue = is_active_lvalue(e); if (write_probe && lvalue) diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index ec20282a..a07e08b8 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -120,7 +120,7 @@ utrace_derived_probe::utrace_derived_probe (systemtap_session &s, { // Expand local variables in the probe body utrace_var_expanding_visitor v (s, l, name, flags); - this->body = v.require (this->body); + v.replace (this->body); target_symbol_seen = v.target_symbol_seen; // If during target-variable-expanding the probe, we added a new block @@ -407,54 +407,80 @@ utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e) void utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) { - string argnum_s = e->base_name.substr(4,e->base_name.length()-4); - int argnum = lex_cast<int>(argnum_s); - if (flags != UDPF_SYSCALL) - throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", e->tok); + throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN or $$parms.", e->tok); - if (e->components.size() > 0) + if (e->base_name == "$$parms") { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("utrace target variable '$argN' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("utrace target variable '$argN' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of utrace target variable '$argN'", - e->tok); - break; - } - } - - // FIXME: max argnument number should not be hardcoded. - if (argnum < 1 || argnum > 6) - throw semantic_error ("invalid syscall argument number (1-6)", e->tok); - - bool lvalue = is_active_lvalue(e); - if (lvalue) - throw semantic_error("utrace '$argN' variable is read-only", e->tok); - - // Remember that we've seen a target variable. - target_symbol_seen = true; - - // We're going to substitute a synthesized '_utrace_syscall_arg' - // function call for the '$argN' reference. - functioncall* n = new functioncall; - n->tok = e->tok; - n->function = "_utrace_syscall_arg"; - n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - - literal_number *num = new literal_number(argnum - 1); - num->tok = e->tok; - n->args.push_back(num); - - provide (n); + // copy from tracepoint + print_format* pf = new print_format; + token* pf_tok = new token(*e->tok); + pf_tok->content = "sprintf"; + pf->tok = pf_tok; + pf->print_to_stream = false; + pf->print_with_format = true; + pf->print_with_delim = false; + pf->print_with_newline = false; + pf->print_char = false; + + target_symbol_seen = true; + + for (unsigned i = 0; i < 6; ++i) + { + if (i > 0) + pf->raw_components += " "; + pf->raw_components += "$arg" + lex_cast<string>(i+1); + target_symbol *tsym = new target_symbol; + tsym->tok = e->tok; + tsym->base_name = "$arg" + lex_cast<string>(i+1); + tsym->saved_conversion_error = 0; + pf->raw_components += "=%#x"; //FIXME: missing type info + + functioncall* n = new functioncall; //same as the following + n->tok = e->tok; + n->function = "_utrace_syscall_arg"; + n->referent = 0; + literal_number *num = new literal_number(i); + num->tok = e->tok; + n->args.push_back(num); + + pf->args.push_back(n); + } + pf->components = print_format::string_to_components(pf->raw_components); + + provide (pf); + } + else // $argN + { + string argnum_s = e->base_name.substr(4,e->base_name.length()-4); + int argnum = lex_cast<int>(argnum_s); + + e->assert_no_components("utrace"); + + // FIXME: max argnument number should not be hardcoded. + if (argnum < 1 || argnum > 6) + throw semantic_error ("invalid syscall argument number (1-6)", e->tok); + + bool lvalue = is_active_lvalue(e); + if (lvalue) + throw semantic_error("utrace '$argN' variable is read-only", e->tok); + + // Remember that we've seen a target variable. + target_symbol_seen = true; + + // We're going to substitute a synthesized '_utrace_syscall_arg' + // function call for the '$argN' reference. + functioncall* n = new functioncall; + n->tok = e->tok; + n->function = "_utrace_syscall_arg"; + n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + + literal_number *num = new literal_number(argnum - 1); + num->tok = e->tok; + n->args.push_back(num); + + provide (n); + } } void @@ -462,24 +488,7 @@ utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) { string sname = e->base_name; - if (e->components.size() > 0) - { - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("utrace target variable '" + sname + "' may not be used as array", - e->tok); - break; - case target_symbol::comp_struct_member: - throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure", - e->tok); - break; - default: - throw semantic_error ("invalid use of utrace target variable '" + sname + "'", - e->tok); - break; - } - } + e->assert_no_components("utrace"); bool lvalue = is_active_lvalue(e); if (lvalue) @@ -542,12 +551,12 @@ utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e) if (e->addressof) throw semantic_error("cannot take address of utrace variable", e->tok); - if (e->base_name.substr(0,4) == "$arg") + if (e->base_name.substr(0,4) == "$arg" || e->base_name == "$$parms") visit_target_symbol_arg(e); else if (e->base_name == "$syscall" || e->base_name == "$return") visit_target_symbol_context(e); else - throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected", + throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return, $argN or $$parms expected", e->tok); } diff --git a/tapset/stap_staticmarkers.stp b/tapset/stap_staticmarkers.stp new file mode 100644 index 00000000..ff295771 --- /dev/null +++ b/tapset/stap_staticmarkers.stp @@ -0,0 +1,267 @@ +// stap/staprun/stapio static probes tapset +// +// Copyright (C) 2009 Red Hat Inc. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +/** + * probes stap.pass0, stap.pass0.end + * @session: the systemtap_session variable s + * + * pass0 fires after command line arguments have been parsed. + * pass0.end fires just before the gettimeofday() call for pass1. + */ +probe stap.pass0 = process("stap").mark("pass0__start") { + session = $arg1 +} +probe stap.pass0.end = process("stap").mark("pass0__end") { + session = $arg1 +} + +/** + * probes stap.pass1a, stap.pass1b, stap.pass1.end + * @session: the systemtap_session variable s + * + * pass1a fires just after the call to gettimeofday(), before the + * user script is parsed. + * pass1b fires just before the library scripts are parsed. + * pass1.end fires just before the jump to cleanup if s.last_pass = 1. + */ +probe stap.pass1a = process("stap").mark("pass1a__start") { + session = $arg1 +} +probe stap.pass1b = process("stap").mark("pass1b__start") { + session = $arg1 +} +probe stap.pass1.end = process("stap").mark("pass1__end") { + session = $arg1 +} + +/** + * probes stap.pass2, stap.pass2.end + * @session: the systemtap_session variable s + * + * pass2 fires just after the call to gettimeofday(), just before the + * call to semantic_pass. + * pass2.end fires just before the jump to cleanup if s.last_pass = 2 + */ +probe stap.pass2 = process("stap").mark("pass2__start") { + session = $arg1 +} +probe stap.pass2.end = process("stap").mark("pass2__end") { + session = $arg1 +} + +/** + * probes stap.pass3, stap.pass3.end + * @session: the systemtap_session variable s + * + * pass3 fires just after the call to gettimeofday(), just before the + * call to translate_pass. + * pass3.end fires just before the jump to cleanup if s.last_pass = 3 + */ +probe stap.pass3 = process("stap").mark("pass3__start") { + session = $arg1 +} +probe stap.pass3.end = process("stap").mark("pass3__end") { + session = $arg1 +} + +/** + * probes stap.pass4, stap.pass4.end + * @session: the systemtap_session variable s + * + * pass4 fires just after the call to gettimeofday(), just before the + * call to compile_pass. + * pass4.end fires just before the jump to cleanup if s.last_pass = 4 + */ +probe stap.pass4 = process("stap").mark("pass4__start") { + session = $arg1 +} +probe stap.pass4.end = process("stap").mark("pass4__end") { + session = $arg1 +} + +/** + * probes stap.pass5, stap.pass5.end + * @session: the systemtap_session variable s + * + * pass5 fires just after the call to gettimeofday(), just before the + * call to run_pass. + * pass5.end fires just before the cleanup label + */ +probe stap.pass5 = process("stap").mark("pass5__start") { + session = $arg1 +} +probe stap.pass5.end = process("stap").mark("pass5__end") { + session = $arg1 +} + +/** + * probes stap.pass6, stap.pass6.end + * @session: the systemtap_session variable s + * + * pass6 fires just after the cleanup label, essentially the same spot + * as pass5.end + * pass6.end fires just before main's return. + */ +probe stap.pass6 = process("stap").mark("pass6__start") { + session = $arg1 +} +probe stap.pass6.end = process("stap").mark("pass6__end") { + session = $arg1 +} + +/** + * probe stap.cache_clean + * @path: the path to the .ko/.c file being removed + * + * Fires just before the call to unlink the module/source file. + */ +probe stap.cache_clean = process("stap").mark("cache__clean") { + path = user_string($arg1) +} + +/** + * probe stap.cache_add_mod + * @source_path: the path the .ko file is coming from (incl filename) + * @dest_path: the path the .ko file is going to (incl filename) + * + * Fires just before the file is actually moved. Note: if moving fails, + * cache_add_src and cache_add_nss will not fire. + */ +probe stap.cache_add_mod = process("stap").mark("cache__add__module") { + source_path = user_string($arg1) + dest_path = user_string($arg2) +} + +/** + * probe stap.cache_add_src + * @source_path: the path the .c file is coming from (incl filename) + * @dest_path: the path the .c file is going to (incl filename) + * + * Fires just before the file is actually moved. Note: if moving the + * kernel module fails, this probe will not fire. + */ +probe stap.cache_add_src = process("stap").mark("cache__add__source") { + source_path = user_string($arg1) + dest_path = user_string($arg2) +} + +/** + * probe stap.cache_add_nss + * @source_path: the path the .sgn file is coming from (incl filename) + * @dest_path: the path the .sgn file is coming from (incl filename) + * + * Fires just before the file is actually moved. Note: stap must compiled + * with NSS support; if moving the kernel module fails, this probe will + * not fire. + */ +probe stap.cache_add_nss = process("stap").mark("cache__add__nss") ? { + source_path = user_string($arg1) + dest_path = user_string($arg2) +} + +/** + * probe stap.cache_get + * @source_path: the path of the .c source file + * @module_path: the path of the .ko kernel module file + * + * Fires just before the return of get_from_cache, when the cache grab + * is successful. + */ +probe stap.cache_get = process("stap").mark("cache__get") { + source_path = user_string($arg1) + module_path = user_string($arg2) +} + +/** + * probe stap.system + * @command: the command string to be run by posix_spawn (as sh -c <str>) + * + * Fires at the entry of the stap_system command. + */ +probe stap.system = process("stap").mark("stap_system__start") { + command = user_string($arg1) +} + +/** + * probe stap.system.spawn + * @ret: the return value from posix_spawn + * @pid: the pid of the spawned process + * + * Fires just after the call to posix_spawn. + */ +probe stap.system.spawn = process("stap").mark("stap_system__spawn") { + /* posix_spawn(3p) for meaning of ret */ + ret = $arg1 + pid = $arg2 +} + +/** + * probe stap.system.return + * @ret: a return code associated with running waitpid on the spawned process; + * a non-zero value indicates error + * + * Fires just before the return of the stap_system function, after waitpid. + */ +probe stap.system.return = process("stap").mark("stap_system__complete") { + ret = $arg1 +} + +/** + * probe staprun.insert_module + * @path: the full path to the .ko kernel module about to be inserted + * + * Fires just before the call to insert the module. + */ +probe staprun.insert_module = process("staprun").mark("insert__module") { + path = user_string($arg1) +} + +/** + * probe staprun.remove_module + * @name: the stap module name to be removed (without the .ko extension) + * + * Fires just before the call to remove the module. + */ +probe staprun.remove_module = process("staprun").mark("remove__module") { + name = user_string($arg1) +} + +/** + * probe staprun.send_control_message + * @type: type of message being send; defined in runtime/transport/transport_msgs.h + * @data: a ptr to a binary blob of data sent as the control message + * @len: the length (in bytes) of the data blob + * + * Fires at the beginning of the send_request function. + */ +probe staprun.send_control_message = process("staprun").mark("send__ctlmsg") { + type = $arg1 + data = $arg2 + len = $arg3 +} + +/** + * probe stapio.receive_control_message + * @type: type of message being send; defined in runtime/transport/transport_msgs.h + * @data: a ptr to a binary blob of data sent as the control message + * @len: the length (in bytes) of the data blob + * + * Fires just after a message was receieved and before it's processed. + */ +/* + *** Due to stapio not being in a user's PATH and the build environment of *** + *** stap, there is no immediate 'good' way to insert the correct path here *** + *** so comment out this probe. Note however, the static marker is still *** + *** present in source. *** +probe stapio.receive_control_message = process("@libexecdir@/systemtap/stapio").mark("recv__ctlmsg") { + type = $arg1 + data = $arg2 + len = $arg3 +} +*/ diff --git a/tapsets.cxx b/tapsets.cxx index c8bc4d35..b1ca2998 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -290,8 +290,10 @@ symbol_table void add_symbol(const char *name, bool weak, Dwarf_Addr addr, Dwarf_Addr *high_addr); enum info_status read_symbols(FILE *f, const string& path); - enum info_status read_from_elf_file(const string& path); - enum info_status read_from_text_file(const string& path); + enum info_status read_from_elf_file(const string& path, + const systemtap_session &sess); + enum info_status read_from_text_file(const string& path, + const systemtap_session &sess); enum info_status get_from_elf(); void prepare_section_rejection(Dwfl_Module *mod); bool reject_section(GElf_Word section); @@ -351,6 +353,10 @@ struct dwarf_derived_probe: public derived_probe void join_group (systemtap_session& s); void emit_probe_local_init(translator_output * o); + string args; + void saveargs(Dwarf_Die* scope_die); + void printargs(std::ostream &o) const; + // Pattern registration helpers. static void register_statement_variants(match_node * root, dwarf_builder * dw, @@ -393,6 +399,10 @@ struct uprobe_derived_probe: public derived_probe Dwarf_Addr addr, bool return_p); + string args; + void saveargs(Dwarf_Die* scope_die); + void printargs(std::ostream &o) const; + void printsig (std::ostream &o) const; void join_group (systemtap_session& s); }; @@ -811,10 +821,11 @@ dwarf_query::query_module_symtab() fi = sym_table->get_func_containing_address(addr); if (!fi) { - cerr << "Warning: address " - << hex << addr << dec - << " out of range for module " - << dw.module_name; + if (! sess.suppress_warnings) + cerr << "Warning: address " + << hex << addr << dec + << " out of range for module " + << dw.module_name; return; } if (!null_die(&fi->die)) @@ -823,10 +834,11 @@ dwarf_query::query_module_symtab() // the indicated function, but query_module_dwarf() didn't // match addr to any compilation unit, so addr must be // above that cu's address range. - cerr << "Warning: address " - << hex << addr << dec - << " maps to no known compilation unit in module " - << dw.module_name; + if (! sess.suppress_warnings) + cerr << "Warning: address " + << hex << addr << dec + << " maps to no known compilation unit in module " + << dw.module_name; return; } query_func_info(fi->addr, *fi, this); @@ -1408,6 +1420,9 @@ query_cu (Dwarf_Die * cudie, void * arg) << " does not match the beginning of a statement"; if (address_line) msg << " (try 0x" << hex << lineaddr << ")"; + else + msg << " (no line info found for '" << q->dw.cu_name + << "', in module '" << q->dw.module_name << "')"; if (! q->sess.guru_mode) throw semantic_error(msg.str()); else if (! q->sess.suppress_warnings) @@ -1699,6 +1714,8 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a): q(q), scope_die(sd), addr(a), add_block(NULL), add_probe(NULL), visited(false) {} + void visit_target_symbol_saved_return (target_symbol* e); + void visit_target_symbol_context (target_symbol* e); void visit_target_symbol (target_symbol* e); void visit_cast_op (cast_op* e); }; @@ -1758,415 +1775,432 @@ var_expanding_visitor::visit_assignment (assignment* e) void -dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) -{ - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - visited = true; - - bool lvalue = is_active_lvalue(e); - if (lvalue && !q.sess.guru_mode) - throw semantic_error("write to target variable not permitted", e->tok); - - // See if we need to generate a new probe to save/access function - // parameters from a return probe. PR 1382. - if (q.has_return - && e->base_name != "$return" // not the special return-value variable handled below - && e->base_name != "$$return") // nor the other special variable handled below +dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e) +{ + // Get the full name of the target symbol. + stringstream ts_name_stream; + e->print(ts_name_stream); + string ts_name = ts_name_stream.str(); + + // Check and make sure we haven't already seen this target + // variable in this return probe. If we have, just return our + // last replacement. + map<string, symbol *>::iterator i = return_ts_map.find(ts_name); + if (i != return_ts_map.end()) { - if (lvalue) - throw semantic_error("write to target variable not permitted in .return probes", e->tok); - - // Get the full name of the target symbol. - stringstream ts_name_stream; - e->print(ts_name_stream); - string ts_name = ts_name_stream.str(); - - // Check and make sure we haven't already seen this target - // variable in this return probe. If we have, just return our - // last replacement. - map<string, symbol *>::iterator i = return_ts_map.find(ts_name); - if (i != return_ts_map.end()) - { - provide (i->second); - return; - } - - // We've got to do several things here to handle target - // variables in return probes. + provide (i->second); + return; + } - // (1) Synthesize two global arrays. One is the cache of the - // target variable and the other contains a thread specific - // nesting level counter. The arrays will look like - // this: - // - // _dwarf_tvar_{name}_{num} - // _dwarf_tvar_{name}_{num}_ctr + // We've got to do several things here to handle target + // variables in return probes. - string aname = (string("_dwarf_tvar_") - + e->base_name.substr(1) - + "_" + lex_cast<string>(tick++)); - vardecl* vd = new vardecl; - vd->name = aname; - vd->tok = e->tok; - q.sess.globals.push_back (vd); + // (1) Synthesize two global arrays. One is the cache of the + // target variable and the other contains a thread specific + // nesting level counter. The arrays will look like + // this: + // + // _dwarf_tvar_{name}_{num} + // _dwarf_tvar_{name}_{num}_ctr + + string aname = (string("_dwarf_tvar_") + + e->base_name.substr(1) + + "_" + lex_cast<string>(tick++)); + vardecl* vd = new vardecl; + vd->name = aname; + vd->tok = e->tok; + q.sess.globals.push_back (vd); + + string ctrname = aname + "_ctr"; + vd = new vardecl; + vd->name = ctrname; + vd->tok = e->tok; + q.sess.globals.push_back (vd); + + // (2) Create a new code block we're going to insert at the + // beginning of this probe to get the cached value into a + // temporary variable. We'll replace the target variable + // reference with the temporary variable reference. The code + // will look like this: + // + // _dwarf_tvar_tid = tid() + // _dwarf_tvar_{name}_{num}_tmp + // = _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] + // delete _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]--] + // if (! _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]) + // delete _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid] + + // (2a) Synthesize the tid temporary expression, which will look + // like this: + // + // _dwarf_tvar_tid = tid() + symbol* tidsym = new symbol; + tidsym->name = string("_dwarf_tvar_tid"); + tidsym->tok = e->tok; - string ctrname = aname + "_ctr"; - vd = new vardecl; - vd->name = ctrname; - vd->tok = e->tok; - q.sess.globals.push_back (vd); - - // (2) Create a new code block we're going to insert at the - // beginning of this probe to get the cached value into a - // temporary variable. We'll replace the target variable - // reference with the temporary variable reference. The code - // will look like this: - // - // _dwarf_tvar_tid = tid() - // _dwarf_tvar_{name}_{num}_tmp - // = _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] - // delete _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]--] - // if (! _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]) - // delete _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid] - - // (2a) Synthesize the tid temporary expression, which will look - // like this: - // - // _dwarf_tvar_tid = tid() - symbol* tidsym = new symbol; - tidsym->name = string("_dwarf_tvar_tid"); - tidsym->tok = e->tok; - - if (add_block == NULL) - { - add_block = new block; - add_block->tok = e->tok; - - // Synthesize a functioncall to grab the thread id. - functioncall* fc = new functioncall; - fc->tok = e->tok; - fc->function = string("tid"); - - // Assign the tid to '_dwarf_tvar_tid'. - assignment* a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = tidsym; - a->right = fc; - - expr_statement* es = new expr_statement; - es->tok = e->tok; - es->value = a; - add_block->statements.push_back (es); - } + if (add_block == NULL) + { + add_block = new block; + add_block->tok = e->tok; - // (2b) Synthesize an array reference and assign it to a - // temporary variable (that we'll use as replacement for the - // target variable reference). It will look like this: - // - // _dwarf_tvar_{name}_{num}_tmp - // = _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] - - arrayindex* ai_tvar_base = new arrayindex; - ai_tvar_base->tok = e->tok; - - symbol* sym = new symbol; - sym->name = aname; - sym->tok = e->tok; - ai_tvar_base->base = sym; - - ai_tvar_base->indexes.push_back(tidsym); - - // We need to create a copy of the array index in its current - // state so we can have 2 variants of it (the original and one - // that post-decrements the second index). - arrayindex* ai_tvar = new arrayindex; - arrayindex* ai_tvar_postdec = new arrayindex; - *ai_tvar = *ai_tvar_base; - *ai_tvar_postdec = *ai_tvar_base; - - // Synthesize the - // "_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]" used as the - // second index into the array. - arrayindex* ai_ctr = new arrayindex; - ai_ctr->tok = e->tok; - - sym = new symbol; - sym->name = ctrname; - sym->tok = e->tok; - ai_ctr->base = sym; - ai_ctr->indexes.push_back(tidsym); - ai_tvar->indexes.push_back(ai_ctr); - - symbol* tmpsym = new symbol; - tmpsym->name = aname + "_tmp"; - tmpsym->tok = e->tok; + // Synthesize a functioncall to grab the thread id. + functioncall* fc = new functioncall; + fc->tok = e->tok; + fc->function = string("tid"); + // Assign the tid to '_dwarf_tvar_tid'. assignment* a = new assignment; a->tok = e->tok; a->op = "="; - a->left = tmpsym; - a->right = ai_tvar; + a->left = tidsym; + a->right = fc; expr_statement* es = new expr_statement; es->tok = e->tok; es->value = a; - add_block->statements.push_back (es); + } - // (2c) Add a post-decrement to the second array index and - // delete the array value. It will look like this: - // - // delete _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]--] - - post_crement* pc = new post_crement; - pc->tok = e->tok; - pc->op = "--"; - pc->operand = ai_ctr; - ai_tvar_postdec->indexes.push_back(pc); - - delete_statement* ds = new delete_statement; - ds->tok = e->tok; - ds->value = ai_tvar_postdec; - - add_block->statements.push_back (ds); - - // (2d) Delete the counter value if it is 0. It will look like - // this: - // if (! _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]) - // delete _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid] - - ds = new delete_statement; - ds->tok = e->tok; - ds->value = ai_ctr; - - unary_expression *ue = new unary_expression; - ue->tok = e->tok; - ue->op = "!"; - ue->operand = ai_ctr; - - if_statement *ifs = new if_statement; - ifs->tok = e->tok; - ifs->condition = ue; - ifs->thenblock = ds; - ifs->elseblock = NULL; - - add_block->statements.push_back (ifs); - - // (3) We need an entry probe that saves the value for us in the - // global array we created. Create the entry probe, which will - // look like this: - // - // probe kernel.function("{function}") { - // _dwarf_tvar_tid = tid() - // _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // ++_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] - // = ${param} - // } - - if (add_probe == NULL) + // (2b) Synthesize an array reference and assign it to a + // temporary variable (that we'll use as replacement for the + // target variable reference). It will look like this: + // + // _dwarf_tvar_{name}_{num}_tmp + // = _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] + + arrayindex* ai_tvar_base = new arrayindex; + ai_tvar_base->tok = e->tok; + + symbol* sym = new symbol; + sym->name = aname; + sym->tok = e->tok; + ai_tvar_base->base = sym; + + ai_tvar_base->indexes.push_back(tidsym); + + // We need to create a copy of the array index in its current + // state so we can have 2 variants of it (the original and one + // that post-decrements the second index). + arrayindex* ai_tvar = new arrayindex; + arrayindex* ai_tvar_postdec = new arrayindex; + *ai_tvar = *ai_tvar_base; + *ai_tvar_postdec = *ai_tvar_base; + + // Synthesize the + // "_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]" used as the + // second index into the array. + arrayindex* ai_ctr = new arrayindex; + ai_ctr->tok = e->tok; + + sym = new symbol; + sym->name = ctrname; + sym->tok = e->tok; + ai_ctr->base = sym; + ai_ctr->indexes.push_back(tidsym); + ai_tvar->indexes.push_back(ai_ctr); + + symbol* tmpsym = new symbol; + tmpsym->name = aname + "_tmp"; + tmpsym->tok = e->tok; + + assignment* a = new assignment; + a->tok = e->tok; + a->op = "="; + a->left = tmpsym; + a->right = ai_tvar; + + expr_statement* es = new expr_statement; + es->tok = e->tok; + es->value = a; + + add_block->statements.push_back (es); + + // (2c) Add a post-decrement to the second array index and + // delete the array value. It will look like this: + // + // delete _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]--] + + post_crement* pc = new post_crement; + pc->tok = e->tok; + pc->op = "--"; + pc->operand = ai_ctr; + ai_tvar_postdec->indexes.push_back(pc); + + delete_statement* ds = new delete_statement; + ds->tok = e->tok; + ds->value = ai_tvar_postdec; + + add_block->statements.push_back (ds); + + // (2d) Delete the counter value if it is 0. It will look like + // this: + // if (! _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]) + // delete _dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid] + + ds = new delete_statement; + ds->tok = e->tok; + ds->value = ai_ctr; + + unary_expression *ue = new unary_expression; + ue->tok = e->tok; + ue->op = "!"; + ue->operand = ai_ctr; + + if_statement *ifs = new if_statement; + ifs->tok = e->tok; + ifs->condition = ue; + ifs->thenblock = ds; + ifs->elseblock = NULL; + + add_block->statements.push_back (ifs); + + // (3) We need an entry probe that saves the value for us in the + // global array we created. Create the entry probe, which will + // look like this: + // + // probe kernel.function("{function}") { + // _dwarf_tvar_tid = tid() + // _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // ++_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] + // = ${param} + // } + + if (add_probe == NULL) + { + add_probe = new probe; + add_probe->tok = e->tok; + + // We need the name of the current probe point, minus the + // ".return" (or anything after it, such as ".maxactive(N)"). + // Create a new probe point, copying all the components, + // stopping when we see the ".return" component. + probe_point* pp = new probe_point; + for (unsigned c = 0; c < q.base_loc->components.size(); c++) { - add_probe = new probe; - add_probe->tok = e->tok; - - // We need the name of the current probe point, minus the - // ".return" (or anything after it, such as ".maxactive(N)"). - // Create a new probe point, copying all the components, - // stopping when we see the ".return" component. - probe_point* pp = new probe_point; - for (unsigned c = 0; c < q.base_loc->components.size(); c++) - { - if (q.base_loc->components[c]->functor == "return") - break; - else - pp->components.push_back(q.base_loc->components[c]); - } - pp->tok = e->tok; - pp->optional = q.base_loc->optional; - add_probe->locations.push_back(pp); - - add_probe->body = new block; - add_probe->body->tok = e->tok; - - // Synthesize a functioncall to grab the thread id. - functioncall* fc = new functioncall; - fc->tok = e->tok; - fc->function = string("tid"); - - // Assign the tid to '_dwarf_tvar_tid'. - assignment* a = new assignment; - a->tok = e->tok; - a->op = "="; - a->left = tidsym; - a->right = fc; - - expr_statement* es = new expr_statement; - es->tok = e->tok; - es->value = a; - add_probe->body = new block(add_probe->body, es); - - vardecl* vd = new vardecl; - vd->tok = e->tok; - vd->name = tidsym->name; - vd->type = pe_long; - vd->set_arity(0); - add_probe->locals.push_back(vd); - } + if (q.base_loc->components[c]->functor == "return") + break; + else + pp->components.push_back(q.base_loc->components[c]); + } + pp->tok = e->tok; + pp->optional = q.base_loc->optional; + add_probe->locations.push_back(pp); - // Save the value, like this: - // _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, - // ++_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] - // = ${param} - arrayindex* ai_tvar_preinc = new arrayindex; - *ai_tvar_preinc = *ai_tvar_base; + add_probe->body = new block; + add_probe->body->tok = e->tok; - pre_crement* preinc = new pre_crement; - preinc->tok = e->tok; - preinc->op = "++"; - preinc->operand = ai_ctr; - ai_tvar_preinc->indexes.push_back(preinc); + // Synthesize a functioncall to grab the thread id. + functioncall* fc = new functioncall; + fc->tok = e->tok; + fc->function = string("tid"); - a = new assignment; + // Assign the tid to '_dwarf_tvar_tid'. + assignment* a = new assignment; a->tok = e->tok; a->op = "="; - a->left = ai_tvar_preinc; - a->right = e; + a->left = tidsym; + a->right = fc; - es = new expr_statement; + expr_statement* es = new expr_statement; es->tok = e->tok; es->value = a; - add_probe->body = new block(add_probe->body, es); - // (4) Provide the '_dwarf_tvar_{name}_{num}_tmp' variable to - // our parent so it can be used as a substitute for the target - // symbol. - provide (tmpsym); - - // (5) Remember this replacement since we might be able to reuse - // it later if the same return probe references this target - // symbol again. - return_ts_map[ts_name] = tmpsym; - return; + vardecl* vd = new vardecl; + vd->tok = e->tok; + vd->name = tidsym->name; + vd->type = pe_long; + vd->set_arity(0); + add_probe->locals.push_back(vd); } - if (e->base_name == "$$vars" - || e->base_name == "$$parms" - || e->base_name == "$$locals" - || (q.has_return && (e->base_name == "$$return"))) - { - Dwarf_Die *scopes; - if (dwarf_getscopes_die (scope_die, &scopes) == 0) - return; - - if (e->addressof) - throw semantic_error("cannot take address of context variable", e->tok); - - target_symbol *tsym = new target_symbol; - print_format* pf = new print_format; - - // Convert $$parms to sprintf of a list of parms and active local vars - // which we recursively evaluate - - // NB: we synthesize a new token here rather than reusing - // e->tok, because print_format::print likes to use - // its tok->content. - token* pf_tok = new token; - pf_tok->location = e->tok->location; - pf_tok->type = tok_identifier; - pf_tok->content = "sprint"; + // Save the value, like this: + // _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, + // ++_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] + // = ${param} + arrayindex* ai_tvar_preinc = new arrayindex; + *ai_tvar_preinc = *ai_tvar_base; + + pre_crement* preinc = new pre_crement; + preinc->tok = e->tok; + preinc->op = "++"; + preinc->operand = ai_ctr; + ai_tvar_preinc->indexes.push_back(preinc); + + a = new assignment; + a->tok = e->tok; + a->op = "="; + a->left = ai_tvar_preinc; + a->right = e; + + es = new expr_statement; + es->tok = e->tok; + es->value = a; + + add_probe->body = new block(add_probe->body, es); + + // (4) Provide the '_dwarf_tvar_{name}_{num}_tmp' variable to + // our parent so it can be used as a substitute for the target + // symbol. + provide (tmpsym); + + // (5) Remember this replacement since we might be able to reuse + // it later if the same return probe references this target + // symbol again. + return_ts_map[ts_name] = tmpsym; +} - pf->tok = pf_tok; - pf->print_to_stream = false; - pf->print_with_format = true; - pf->print_with_delim = false; - pf->print_with_newline = false; - pf->print_char = false; - if (q.has_return && (e->base_name == "$$return")) +void +dwarf_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) +{ + Dwarf_Die *scopes; + if (dwarf_getscopes_die (scope_die, &scopes) == 0) + return; + auto_free free_scopes(scopes); + + target_symbol *tsym = new target_symbol; + print_format* pf = new print_format; + + // Convert $$parms to sprintf of a list of parms and active local vars + // which we recursively evaluate + + // NB: we synthesize a new token here rather than reusing + // e->tok, because print_format::print likes to use + // its tok->content. + token* pf_tok = new token; + pf_tok->location = e->tok->location; + pf_tok->type = tok_identifier; + pf_tok->content = "sprint"; + + pf->tok = pf_tok; + pf->print_to_stream = false; + pf->print_with_format = true; + pf->print_with_delim = false; + pf->print_with_newline = false; + pf->print_char = false; + + if (q.has_return && (e->base_name == "$$return")) + { + tsym->tok = e->tok; + tsym->base_name = "$return"; + + // Ignore any variable that isn't accessible. + tsym->saved_conversion_error = 0; + expression *texp = tsym; + replace (texp); // NB: throws nothing ... + if (tsym->saved_conversion_error) // ... but this is how we know it happened. { - tsym->tok = e->tok; - tsym->base_name = "$return"; - - // Ignore any variable that isn't accessible. - tsym->saved_conversion_error = 0; - expression *texp = tsym; - texp = require (texp); // NB: throws nothing ... - if (tsym->saved_conversion_error) // ... but this is how we know it happened. - { - } - else - { - pf->raw_components += "return"; - pf->raw_components += "=%#x "; - pf->args.push_back(texp); - } } else { - // non-.return probe: support $$parms, $$vars, $$locals - Dwarf_Die result; - if (dwarf_child (&scopes[0], &result) == 0) - do + pf->raw_components += "return"; + pf->raw_components += "=%#x "; + pf->args.push_back(texp); + } + } + else + { + // non-.return probe: support $$parms, $$vars, $$locals + Dwarf_Die result; + if (dwarf_child (&scopes[0], &result) == 0) + do + { + switch (dwarf_tag (&result)) { - switch (dwarf_tag (&result)) - { - case DW_TAG_variable: - if (e->base_name == "$$parms") - continue; - break; - case DW_TAG_formal_parameter: - if (e->base_name == "$$locals") - continue; - break; - - default: - continue; - } + case DW_TAG_variable: + if (e->base_name == "$$parms") + continue; + break; + case DW_TAG_formal_parameter: + if (e->base_name == "$$locals") + continue; + break; + + default: + continue; + } - const char *diename = dwarf_diename (&result); - if (! diename) continue; + const char *diename = dwarf_diename (&result); + if (! diename) continue; - tsym->tok = e->tok; - tsym->base_name = "$"; - tsym->base_name += diename; + tsym->tok = e->tok; + tsym->base_name = "$"; + tsym->base_name += diename; - // Ignore any variable that isn't accessible. - tsym->saved_conversion_error = 0; - expression *texp = tsym; - texp = require (texp); // NB: throws nothing ... - if (tsym->saved_conversion_error) // ... but this is how we know it happened. - { - if (q.sess.verbose>2) - { - for (semantic_error *c = tsym->saved_conversion_error; - c != 0; - c = c->chain) { - clog << "variable location problem: " << c->what() << endl; - } - } - - pf->raw_components += diename; - pf->raw_components += "=? "; - } - else + // Ignore any variable that isn't accessible. + tsym->saved_conversion_error = 0; + expression *texp = tsym; + replace (texp); // NB: throws nothing ... + if (tsym->saved_conversion_error) // ... but this is how we know it happened. + { + if (q.sess.verbose>2) { - pf->raw_components += diename; - pf->raw_components += "=%#x "; - pf->args.push_back(texp); + for (semantic_error *c = tsym->saved_conversion_error; + c != 0; + c = c->chain) { + clog << "variable location problem: " << c->what() << endl; + } } + + pf->raw_components += diename; + pf->raw_components += "=? "; } - while (dwarf_siblingof (&result, &result) == 0); - } + else + { + pf->raw_components += diename; + pf->raw_components += "=%#x "; + pf->args.push_back(texp); + } + } + while (dwarf_siblingof (&result, &result) == 0); + } - pf->components = print_format::string_to_components(pf->raw_components); - provide (pf); + pf->components = print_format::string_to_components(pf->raw_components); + provide (pf); +} + +void +dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) +{ + assert(e->base_name.size() > 0 && e->base_name[0] == '$'); + visited = true; + + bool lvalue = is_active_lvalue(e); + if (lvalue && !q.sess.guru_mode) + throw semantic_error("write to target variable not permitted", e->tok); + + // See if we need to generate a new probe to save/access function + // parameters from a return probe. PR 1382. + if (q.has_return + && e->base_name != "$return" // not the special return-value variable handled below + && e->base_name != "$$return") // nor the other special variable handled below + { + if (lvalue) + throw semantic_error("write to target variable not permitted in .return probes", e->tok); + + visit_target_symbol_saved_return(e); + return; + } + + if (e->base_name == "$$vars" + || e->base_name == "$$parms" + || e->base_name == "$$locals" + || (q.has_return && (e->base_name == "$$return"))) + { + if (lvalue) + throw semantic_error("cannot write to context variable", e->tok); + + if (e->addressof) + throw semantic_error("cannot take address of context variable", e->tok); + + visit_target_symbol_context(e); return; } @@ -2213,7 +2247,6 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) // quietly. provide (e); semantic_error* saveme = new semantic_error (er); // copy it - saveme->tok1 = e->tok; // XXX: token not passed to q.dw code generation routines // NB: we can have multiple errors, since a $target variable // may be expanded in several different contexts: // function ("*") { $var } @@ -2238,6 +2271,18 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) fdecl->name = fname; fdecl->body = ec; + + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + { + vardecl *v = new vardecl; + v->type = pe_long; + v->name = "index" + lex_cast<string>(i); + v->tok = e->tok; + fdecl->formal_args.push_back(v); + } + if (lvalue) { // Modify the fdecl so it carries a single pe_long formal @@ -2262,6 +2307,11 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) n->function = fname; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + n->args.push_back(require(e->components[i].expr_index)); + if (lvalue) { // Provide the functioncall to our parent, so that it can be @@ -2494,6 +2544,17 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) v1->tok = e->tok; fdecl->formal_args.push_back(v1); + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + { + vardecl *v = new vardecl; + v->type = pe_long; + v->name = "index" + lex_cast<string>(i); + v->tok = e->tok; + fdecl->formal_args.push_back(v); + } + if (lvalue) { // Modify the fdecl so it carries a second pe_long formal @@ -2522,6 +2583,11 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session n->args.push_back(e->operand); + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + n->args.push_back(require(e->components[i].expr_index)); + if (lvalue) { // Provide the functioncall to our parent, so that it can be @@ -2604,7 +2670,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, if (!null_die(scope_die)) { dwarf_var_expanding_visitor v (q, scope_die, dwfl_addr); - this->body = v.require (this->body); + v.replace (this->body); this->access_vars = v.visited; // If during target-variable-expanding the probe, we added a new block @@ -2622,6 +2688,10 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, } // else - null scope_die - $target variables will produce an error during translate phase + // Save the local variables for listing mode + if (q.sess.listing_mode_vars) + saveargs(scope_die); + // Reset the sole element of the "locations" vector as a // "reverse-engineered" form of the incoming (q.base_loc) probe // point. This allows a user to see what function / file / line @@ -2686,6 +2756,66 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, } +static bool dwarf_type_name(Dwarf_Die& type_die, string& c_type); + +void +dwarf_derived_probe::saveargs(Dwarf_Die* scope_die) +{ + Dwarf_Die *scopes; + if (!null_die(scope_die) && dwarf_getscopes_die (scope_die, &scopes) == 0) + return; + auto_free free_scopes(scopes); + + stringstream argstream; + string type_name; + Dwarf_Attribute type_attr; + Dwarf_Die type_die; + + if (has_return && + dwarf_attr_integrate (scope_die, DW_AT_type, &type_attr) && + dwarf_formref_die (&type_attr, &type_die) && + dwarf_type_name(type_die, type_name)) + argstream << " $return:" << type_name; + + Dwarf_Die arg; + if (dwarf_child (&scopes[0], &arg) == 0) + do + { + switch (dwarf_tag (&arg)) + { + case DW_TAG_variable: + case DW_TAG_formal_parameter: + break; + + default: + continue; + } + + const char *arg_name = dwarf_diename (&arg); + if (!arg_name) + continue; + + type_name.clear(); + if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr) || + !dwarf_formref_die (&type_attr, &type_die) || + !dwarf_type_name(type_die, type_name)) + continue; + + argstream << " $" << arg_name << ":" << type_name; + } + while (dwarf_siblingof (&arg, &arg) == 0); + + args = argstream.str(); +} + + +void +dwarf_derived_probe::printargs(std::ostream &o) const +{ + o << args; +} + + void dwarf_derived_probe::register_statement_variants(match_node * root, dwarf_builder * dw, @@ -2896,7 +3026,18 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << "];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; + + // Make it look like the IP is set as it wouldn't have been replaced + // by a breakpoint instruction when calling real probe handler. Reset + // IP regs on return, so we don't confuse kprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = (unsigned long) inst->addr;"; s.op->newline() << "(*sdp->ph) (c);"; + s.op->newline() << "REG_IP(regs) = kprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline() << "return 0;"; s.op->newline(-1) << "}"; @@ -2919,7 +3060,18 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; s.op->newline() << "c->pi = inst;"; // for assisting runtime's backtrace logic + + // Make it look like the IP is set as it wouldn't have been replaced + // by a breakpoint instruction when calling real probe handler. Reset + // IP regs on return, so we don't confuse kprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = (unsigned long) inst->rp->kp.addr;"; s.op->newline() << "(*sdp->ph) (c);"; + s.op->newline() << "REG_IP(regs) = kprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline() << "return 0;"; s.op->newline(-1) << "}"; @@ -3166,7 +3318,7 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) cast->type = probe_name + "_arg" + lex_cast<string>(argno); cast->module = process_name; - provide(cast); + cast->visit(this); } @@ -3247,7 +3399,7 @@ sdt_query::handle_query_module() sdt_var_expanding_visitor svv (module_val, probe_name, probe_arg, have_reg_args, probe_type == utrace_type); - new_base->body = svv.require (new_base->body); + svv.replace (new_base->body); unsigned i = results.size(); @@ -3693,7 +3845,8 @@ symbol_table::read_symbols(FILE *f, const string& path) // that gives us raw addresses -- which we need for modules -- whereas // nm provides the address relative to the beginning of the section. enum info_status -symbol_table::read_from_elf_file(const string &path) +symbol_table::read_from_elf_file(const string &path, + const systemtap_session &sess) { FILE *f; string cmd = string("/usr/bin/nm -n --defined-only ") + path; @@ -3708,7 +3861,7 @@ symbol_table::read_from_elf_file(const string &path) enum info_status status = read_symbols(f, path); if (pclose(f) != 0) { - if (status == info_present) + if (status == info_present && ! sess.suppress_warnings) cerr << "Warning: nm cannot read symbol table from " << path; return info_absent; } @@ -3716,13 +3869,15 @@ symbol_table::read_from_elf_file(const string &path) } enum info_status -symbol_table::read_from_text_file(const string& path) +symbol_table::read_from_text_file(const string& path, + const systemtap_session &sess) { FILE *f = fopen(path.c_str(), "r"); if (!f) { - cerr << "Warning: cannot read symbol table from " - << path << " -- " << strerror (errno); + if (! sess.suppress_warnings) + cerr << "Warning: cannot read symbol table from " + << path << " -- " << strerror (errno); return info_absent; } enum info_status status = read_symbols(f, path); @@ -3870,12 +4025,13 @@ module_info::get_symtab(dwarf_query *q) sym_table = new symbol_table(this); if (!elf_path.empty()) { - if (name == TOK_KERNEL && !sess.kernel_symtab_path.empty()) + if (name == TOK_KERNEL && !sess.kernel_symtab_path.empty() + && ! sess.suppress_warnings) cerr << "Warning: reading symbol table from " << elf_path << " -- ignoring " << sess.kernel_symtab_path - << endl ;; + << endl; symtab_status = sym_table->get_from_elf(); } else @@ -3891,7 +4047,7 @@ module_info::get_symtab(dwarf_query *q) else { symtab_status = - sym_table->read_from_text_file(sess.kernel_symtab_path); + sym_table->read_from_text_file(sess.kernel_symtab_path, sess); if (symtab_status == info_present) { sess.sym_kprobes_text_start = @@ -4000,7 +4156,7 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, if (!null_die(scope_die)) { dwarf_var_expanding_visitor v (q, scope_die, dwfl_addr); // XXX: user-space deref's! - this->body = v.require (this->body); + v.replace (this->body); // If during target-variable-expanding the probe, we added a new block // of code, add it to the start of the probe. @@ -4018,6 +4174,10 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, } // else - null scope_die - $target variables will produce an error during translate phase + // Save the local variables for listing mode + if (q.sess.listing_mode_vars) + saveargs(scope_die); + // Reset the sole element of the "locations" vector as a // "reverse-engineered" form of the incoming (q.base_loc) probe // point. This allows a user to see what function / file / line @@ -4092,6 +4252,67 @@ uprobe_derived_probe::uprobe_derived_probe (probe *base, void +uprobe_derived_probe::saveargs(Dwarf_Die* scope_die) +{ + // same as dwarf_derived_probe::saveargs + + Dwarf_Die *scopes; + if (!null_die(scope_die) && dwarf_getscopes_die (scope_die, &scopes) == 0) + return; + auto_free free_scopes(scopes); + + stringstream argstream; + string type_name; + Dwarf_Attribute type_attr; + Dwarf_Die type_die; + + if (return_p && + dwarf_attr_integrate (scope_die, DW_AT_type, &type_attr) && + dwarf_formref_die (&type_attr, &type_die) && + dwarf_type_name(type_die, type_name)) + argstream << " $return:" << type_name; + + Dwarf_Die arg; + if (dwarf_child (&scopes[0], &arg) == 0) + do + { + switch (dwarf_tag (&arg)) + { + case DW_TAG_variable: + case DW_TAG_formal_parameter: + break; + + default: + continue; + } + + const char *arg_name = dwarf_diename (&arg); + if (!arg_name) + continue; + + type_name.clear(); + if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr) || + !dwarf_formref_die (&type_attr, &type_die) || + !dwarf_type_name(type_die, type_name)) + continue; + + argstream << " $" << arg_name << ":" << type_name; + } + while (dwarf_siblingof (&arg, &arg) == 0); + + args = argstream.str(); +} + + +void +uprobe_derived_probe::printargs(std::ostream &o) const +{ + // same as dwarf_derived_probe::printargs + o << args; +} + + +void uprobe_derived_probe::printsig (ostream& o) const { // Same as dwarf_derived_probe. @@ -4222,7 +4443,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "if (sup->spec_index < 0 ||" << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen s.op->newline() << "c->regs = regs;"; + + // Make it look like the IP is set as it would in the actual user + // task when calling real probe handler. Reset IP regs on return, so + // we don't confuse uprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = inst->vaddr;"; s.op->newline() << "(*sups->ph) (c);"; + s.op->newline() << "REG_IP(regs) = uprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; @@ -4234,7 +4466,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen // XXX: kretprobes saves "c->pi = inst;" too s.op->newline() << "c->regs = regs;"; + + // Make it look like the IP is set as it would in the actual user + // task when calling real probe handler. Reset IP regs on return, so + // we don't confuse uprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long uprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = inst->rp->u.vaddr;"; s.op->newline() << "(*sups->ph) (c);"; + s.op->newline() << "REG_IP(regs) = uprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; @@ -4723,7 +4966,18 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << "];"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; + + // Make it look like the IP is set as it wouldn't have been replaced + // by a breakpoint instruction when calling real probe handler. Reset + // IP regs on return, so we don't confuse kprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = (unsigned long) inst->addr;"; s.op->newline() << "(*sdp->ph) (c);"; + s.op->newline() << "REG_IP(regs) = kprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline() << "return 0;"; s.op->newline(-1) << "}"; @@ -4746,7 +5000,18 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; s.op->newline() << "c->pi = inst;"; // for assisting runtime's backtrace logic + + // Make it look like the IP is set as it wouldn't have been replaced + // by a breakpoint instruction when calling real probe handler. Reset + // IP regs on return, so we don't confuse kprobes. PR10458 + s.op->newline() << "{"; + s.op->indent(1); + s.op->newline() << "unsigned long kprobes_ip = REG_IP(c->regs);"; + s.op->newline() << "REG_IP(regs) = (unsigned long) inst->rp->kp.addr;"; s.op->newline() << "(*sdp->ph) (c);"; + s.op->newline() << "REG_IP(regs) = kprobes_ip;"; + s.op->newline(-1) << "}"; + common_probe_entryfn_epilogue (s.op); s.op->newline() << "return 0;"; s.op->newline(-1) << "}"; @@ -5037,19 +5302,8 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) } // make sure we're not dereferencing base types - if (!e->components.empty() && !arg->isptr) - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("tracepoint variable '" + e->base_name - + "' may not be used as array", e->tok); - case target_symbol::comp_struct_member: - throw semantic_error("tracepoint variable '" + e->base_name - + "' may not be used as a structure", e->tok); - default: - throw semantic_error("invalid use of tracepoint variable '" - + e->base_name + "'", e->tok); - } + if (!arg->isptr) + e->assert_no_components("tracepoint"); // we can only write to dereferenced fields, and only if guru mode is on bool lvalue = is_active_lvalue(e); @@ -5098,7 +5352,6 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) // up not being referenced after all, so it can be optimized out // quietly. semantic_error* saveme = new semantic_error (er); // copy it - saveme->tok1 = e->tok; // XXX: token not passed to dw code generation routines // NB: we can have multiple errors, since a target variable // may be expanded in several different contexts: // trace ("*") { $foo->bar } @@ -5115,6 +5368,17 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) v1->tok = e->tok; fdecl->formal_args.push_back(v1); + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + { + vardecl *v = new vardecl; + v->type = pe_long; + v->name = "index" + lex_cast<string>(i); + v->tok = e->tok; + fdecl->formal_args.push_back(v); + } + if (lvalue) { // Modify the fdecl so it carries a pe_long formal @@ -5142,10 +5406,16 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) n->function = fname; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session - // make the original a bare target symbol for the tracepoint value, - // which will be passed into the dwarf dereferencing code - e->components.clear(); - n->args.push_back(require(e)); + // make a copy of the original as a bare target symbol for the tracepoint + // value, which will be passed into the dwarf dereferencing code + target_symbol* e2 = deep_copy_visitor::deep_copy(e); + e2->components.clear(); + n->args.push_back(require(e2)); + + // Any non-literal indexes need to be passed in too. + for (unsigned i = 0; i < e->components.size(); ++i) + if (e->components[i].type == target_symbol::comp_expression_array_index) + n->args.push_back(require(e->components[i].expr_index)); if (lvalue) { @@ -5170,18 +5440,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) if (is_active_lvalue (e)) throw semantic_error("write to tracepoint '" + e->base_name + "' not permitted", e->tok); - if (!e->components.empty()) - switch (e->components[0].first) - { - case target_symbol::comp_literal_array_index: - throw semantic_error("tracepoint '" + e->base_name + "' may not be used as array", - e->tok); - case target_symbol::comp_struct_member: - throw semantic_error("tracepoint '" + e->base_name + "' may not be used as a structure", - e->tok); - default: - throw semantic_error("invalid tracepoint '" + e->base_name + "' use", e->tok); - } + e->assert_no_components("tracepoint"); if (e->base_name == "$$name") { @@ -5287,7 +5546,7 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s, // Now expand the local variables in the probe body tracepoint_var_expanding_visitor v (dw, name, args); - this->body = v.require (this->body); + v.replace (this->body); if (sess.verbose > 2) clog << "tracepoint-based " << name << " tracepoint='" << tracepoint_name diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 737849dc..7358bd2c 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -17,8 +18,9 @@ # Makefile.am --- automake input file for systemtap testsuite VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -42,6 +44,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = SOURCES = DEJATOOL = $(PACKAGE) ACLOCAL = @ACLOCAL@ @@ -141,15 +144,15 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ - cd $(srcdir) && $(AUTOMAKE) --foreign \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -165,9 +168,10 @@ $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENC $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(srcdir) && $(AUTOCONF) + $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): tags: TAGS TAGS: @@ -229,6 +233,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -248,6 +253,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -256,18 +263,28 @@ install-data-am: install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -290,7 +307,7 @@ ps-am: uninstall-am: -.MAKE: install-am install-strip +.MAKE: check-am install-am install-strip .PHONY: all all-am all-local am--refresh check check-DEJAGNU check-am \ check-local clean clean-generic clean-local distclean \ @@ -323,6 +340,7 @@ check-local: installcheck: site.exp -$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU RUNTESTFLAGS="$(RUNTESTFLAGS) --tool_opts \'install $(TOOL_OPTS)\'" if test -n "$(DEJAZILLA)"; then mail $(DEJAZILLA) < systemtap.sum; fi + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/testsuite/aclocal.m4 b/testsuite/aclocal.m4 index a249a8e6..a237cb5a 100644 --- a/testsuite/aclocal.m4 +++ b/testsuite/aclocal.m4 @@ -1,7 +1,7 @@ -# generated automatically by aclocal 1.10.2 -*- Autoconf -*- +# generated automatically by aclocal 1.11 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -31,10 +31,10 @@ To do so, use the procedure documented by the package, typically `autoreconf'.]) # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.10' +[am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.10.2], [], +m4_if([$1], [1.11], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -50,7 +50,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.10.2])dnl +[AM_AUTOMAKE_VERSION([1.11])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -110,14 +110,14 @@ am_aux_dir=`cd $ac_aux_dir && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 8 +# serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- @@ -130,6 +130,7 @@ AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' @@ -146,13 +147,13 @@ fi])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2008 Free Software Foundation, Inc. +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 13 +# serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. @@ -169,7 +170,7 @@ fi])]) # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.60])dnl +[AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl @@ -220,8 +221,8 @@ AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) -AM_PROG_INSTALL_SH -AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. @@ -229,24 +230,37 @@ AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES(OBJC)], - [define([AC_PROG_OBJC], - defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header @@ -269,7 +283,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -280,7 +294,14 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. @@ -307,27 +328,38 @@ AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 4 +# serial 5 +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], -[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) - dnl maintainer-mode is disabled by default - AC_ARG_ENABLE(maintainer-mode, -[ --enable-maintainer-mode enable make rules and dependencies not useful +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful (and sometimes confusing) to the casual installer], - USE_MAINTAINER_MODE=$enableval, - USE_MAINTAINER_MODE=no) + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) - AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE - AC_SUBST(MAINT)dnl + AC_SUBST([MAINT])dnl ] ) @@ -335,14 +367,14 @@ AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 5 +# serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ @@ -359,7 +391,14 @@ AC_SUBST($1)]) AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " @@ -430,14 +469,14 @@ AC_DEFUN([_AM_IF_OPTION], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 4 +# serial 5 # AM_SANITY_CHECK # --------------- @@ -446,16 +485,29 @@ AC_DEFUN([AM_SANITY_CHECK], # Just in case sleep 1 echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` + set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ @@ -508,18 +560,25 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006 Free Software Foundation, Inc. +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. +# serial 2 + # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. diff --git a/testsuite/configure b/testsuite/configure index 09db931f..6199a3c9 100755 --- a/testsuite/configure +++ b/testsuite/configure @@ -1787,7 +1787,7 @@ ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -am__api_version='1.10' +am__api_version='1.11' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or @@ -1887,16 +1887,33 @@ $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + { { $as_echo "$as_me:$LINENO: error: unsafe absolute working directory name" >&5 +$as_echo "$as_me: error: unsafe absolute working directory name" >&2;} + { (exit 1); exit 1; }; };; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + { { $as_echo "$as_me:$LINENO: error: unsafe srcdir value: \`$srcdir'" >&5 +$as_echo "$as_me: error: unsafe srcdir value: \`$srcdir'" >&2;} + { (exit 1); exit 1; }; };; +esac + # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` + set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ @@ -1940,7 +1957,14 @@ program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " @@ -1950,6 +1974,115 @@ else $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + { $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then @@ -2132,108 +2265,6 @@ AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} -install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} - -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:$LINENO: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:$LINENO: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. @@ -2246,6 +2277,7 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + { $as_echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. @@ -2420,6 +2452,7 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then { { $as_echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&5 diff --git a/testsuite/semok/bz10475.stp b/testsuite/semok/bz10475.stp new file mode 100755 index 00000000..ee79b07d --- /dev/null +++ b/testsuite/semok/bz10475.stp @@ -0,0 +1,10 @@ +#! stap -p2 +// bz10475: pointer-array confused about array element size + +// struct file *do_filp_open(int dfd, const char *pathname, +// int open_flag, int mode, int acc_mode) +probe kernel.function("do_filp_open") +{ + // check array access on a "complex" pointer type + println($pathname[0]) +} diff --git a/testsuite/systemtap.base/bz6905.c b/testsuite/systemtap.base/bz6905.c new file mode 100644 index 00000000..bb3f524e --- /dev/null +++ b/testsuite/systemtap.base/bz6905.c @@ -0,0 +1,7 @@ +int main() +{ + int a; + + a = a + 1; + return 0; +} diff --git a/testsuite/systemtap.base/bz6905.exp b/testsuite/systemtap.base/bz6905.exp new file mode 100644 index 00000000..8119159e --- /dev/null +++ b/testsuite/systemtap.base/bz6905.exp @@ -0,0 +1,25 @@ +set test bz6905 + +catch {exec gcc -g -o $test $srcdir/$subdir/$test.c} err +if {$err == "" && [file exists $test]} then { pass "$test compile" } else { fail "$test compile" } + +if {![utrace_p]} { + catch {exec rm -f $test} + untested "$test -p2" + return +} + +set stapexe [exec /usr/bin/which stap] +spawn sudo $stapexe -p2 $srcdir/$subdir/$test.stp +set hint 0 +set probes 0 +expect { + -timeout 60 + -re "# probes" { incr hint; exp_continue } + -re {process.*statement.*} { incr probes; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} +wait +if { $hint == 1 && $probes > 0 } then { pass "$test -p2" } else { fail "$test -p2 ($probes)" } +exec rm -f $test diff --git a/testsuite/systemtap.base/bz6905.stp b/testsuite/systemtap.base/bz6905.stp new file mode 100644 index 00000000..73c7d50c --- /dev/null +++ b/testsuite/systemtap.base/bz6905.stp @@ -0,0 +1,4 @@ +#! stap -p2 +probe process("./bz6905").statement("main@bz6905.c:*") { + printf("ok") +} diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp index c6b098a4..b97d9448 100644 --- a/testsuite/systemtap.base/cmd_parse.exp +++ b/testsuite/systemtap.base/cmd_parse.exp @@ -116,7 +116,7 @@ wait;close spawn stap -L syscall.a* expect { -timeout 60 - -re {(syscall\.a[_a-zA-Z0-9]*(\ [_a-zA-Z0-9\$]+:(string|long|unknown|stats))*\r\n)+} { pass "cmd_parse13" } + -re {(syscall\.a[_a-zA-Z0-9]*(\ [_a-zA-Z0-9\$]+:[^:]+?)+\r\n)+} { pass "cmd_parse13" } timeout {fail "cmd_parse13: unexpected timeout"} eof {fail "cmd_parse13: unexpected EOF"} } diff --git a/testsuite/systemtap.base/crash.exp b/testsuite/systemtap.base/crash.exp index 9c3e5e05..59c8dadd 100644 --- a/testsuite/systemtap.base/crash.exp +++ b/testsuite/systemtap.base/crash.exp @@ -5,7 +5,7 @@ if {![installtest_p]} { untested $test; return } if {![file exists $env(CRASH_LIBDIR)/staplog.so]} { untested "$test - no staplog.so"; return } # Load a test script -spawn stap $srcdir/$subdir/testlog.stp -m testlog +spawn stap -e {probe begin {print("HelloWorld\n")}} -m testlog expect { -timeout 120 "HelloWorld\r\n" { diff --git a/testsuite/systemtap.base/pointer_array.stp b/testsuite/systemtap.base/pointer_array.stp index 1d15ebf4..cd420604 100644 --- a/testsuite/systemtap.base/pointer_array.stp +++ b/testsuite/systemtap.base/pointer_array.stp @@ -2,15 +2,8 @@ probe syscall.execve { if (pid() == target()) { println(user_string($argv[0])) - printf("%c\n", $argv[0][0]) - printf("%c\n", $argv[0][1]) - printf("%c\n", $argv[0][2]) - printf("%c\n", $argv[0][3]) - printf("%c\n", $argv[0][4]) - printf("%c\n", $argv[0][5]) - printf("%c\n", $argv[0][6]) - printf("%c\n", $argv[0][7]) - printf("%c\n", $argv[0][8]) + for (i=0; i<9; ++i) + printf("%c\n", $argv[0][i]) println($argv[0][9]) } } diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp index 8d323a8a..c76503cb 100644 --- a/testsuite/systemtap.base/utrace_p4.exp +++ b/testsuite/systemtap.base/utrace_p4.exp @@ -10,6 +10,7 @@ set begin_script {"probe process(\"/bin/ls\").begin { print(\"ls begin\") }"} set end_script {"probe process(\"/bin/ls\").end { print(\"ls end\") }"} set syscall_script {"probe process(\"/bin/ls\").syscall { printf(\"|%d\", \$syscall) }"} +set syscall_parms_script {"probe process(\"/bin/ls\").syscall { printf(\"|%s\", \$\$parms) }"} set syscall_return_script {"probe process(\"/bin/ls\").syscall.return { printf(\"|%d\", \$syscall) }"} set thread_begin_script {"probe process(\"/bin/ls\").thread.begin { print(\"ls thread.begin\") }"} set thread_end_script {"probe process(\"/bin/ls\").thread.end { print(\"ls thread.end\") }"} @@ -18,6 +19,7 @@ set all_begin_script {"probe process.begin { print(\"begin\") }"} set pid_begin_script {"probe process(123).begin { print(\"123 begin\") }"} set pid_end_script {"probe process(123).end { print(\"123 end\") }"} set pid_syscall_script {"probe process(123).syscall { printf(\"|%d\", \$syscall) }"} +set pid_parms_script {"probe process(123).syscall { printf(\"|%s\", \$\$parms) }"} set pid_syscall_return_script {"probe process(123).syscall.return { printf(\"|%d\", \$syscall) }"} set pid_thread_begin_script {"probe process(123).thread.begin { print(\"123 thread.begin\") }"} set pid_thread_end_script {"probe process(123).thread.end { print(\"123 thread.end\") }"} @@ -129,3 +131,20 @@ if {![utrace_p]} { # Try compiling an system-wide begin script stap_compile $TEST_NAME 1 $all_begin_script } + +set TEST_NAME "UTRACE_P4_08" +if {![utrace_p]} { + untested "$TEST_NAME : no kernel utrace support found" +} else { + # Try compiling a syscall parms script using a path + stap_compile $TEST_NAME 1 $syscall_parms_script +} + +set TEST_NAME "UTRACE_P4_09" +if {![utrace_p]} { + untested "$TEST_NAME : no kernel utrace support found" +} else { + # Try compiling a syscall parms script using a pid + stap_compile $TEST_NAME 1 $pid_parms_script +} + diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp index 3d432dc3..7062bc0d 100644 --- a/testsuite/systemtap.base/utrace_p5.exp +++ b/testsuite/systemtap.base/utrace_p5.exp @@ -89,6 +89,18 @@ set bz6841_script { } set bz6841_script_output ".+ issues syscall \\d+ times\r\n" +set syscall_parms_script { + global syscall_parms_string + probe begin { printf("systemtap starting probe\n") } + probe process.syscall { syscall_parms_string = $$parms exit() } + probe end { printf("systemtap ending probe\n") + printf("%s\n",syscall_parms_string) + delete syscall_parms_string + } +} +set syscall_parms_script_output "(.+arg\[1-6\]=0x\[0-9a-f\]+)+\r\n" + + # Set up our own copy of /bin/cat, to make testing for a particular # executable easy. We can't use 'ln' here, since we might be creating # a cross-device link. We can't use 'ln -s' here, since the kernel @@ -202,5 +214,15 @@ if {![utrace_p]} { -e $bz6841_script } +set TEST_NAME "UTRACE_P5_08" +if {![utrace_p]} { + untested "$TEST_NAME : no kernel utrace support found" +} elseif {![installtest_p]} { + untested "$TEST_NAME" +} else { + set script [format $syscall_parms_script "%s"] + stap_run $TEST_NAME no_load $syscall_parms_script_output -e $script +} + # Cleanup exec rm -f $exepath $multi_exepath diff --git a/testsuite/systemtap.context/uprobe_stmt_num.c b/testsuite/systemtap.context/uprobe_stmt_num.c new file mode 100644 index 00000000..887e572a --- /dev/null +++ b/testsuite/systemtap.context/uprobe_stmt_num.c @@ -0,0 +1,20 @@ +static int +func2 (int x, int y) +{ + return x + y; +} + +static int +func (int arg) +{ + int x = 16; + int y = arg - x; + int z = func2(x, y); + return x + y + z; +} + +int +main (int argc, char *argv[], char *envp[]) +{ + return func(42); +} diff --git a/testsuite/systemtap.context/uprobe_stmt_num.exp b/testsuite/systemtap.context/uprobe_stmt_num.exp new file mode 100644 index 00000000..fbb1126a --- /dev/null +++ b/testsuite/systemtap.context/uprobe_stmt_num.exp @@ -0,0 +1,78 @@ +# Tests whether we can put statement probes on all lines of a function, +# even without debuginfo around (in guru mode currently). PR10454. + +set test "uprobe_stmt_num" + +# Only run on make installcheck and utrace present. +if {! [installtest_p]} { untested "$test"; return } +if {! [utrace_p]} { untested "$test"; return } + +set testpath "$srcdir/$subdir" +set testsrc "$testpath/$test.c" +set testexe "[pwd]/$test" +# We want debug info and no optimization (every line counts). +set testflags "additional_flags=-g additional_flags=-O0" +set teststp "$testpath/$test.stp" + +set res [target_compile $testsrc $testexe executable $testflags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "unable to compile $testsrc" + return +} + +set cmd [concat stap -c $testexe $teststp] +send_log "cmd: $cmd\n" +catch {eval exec $cmd} output +send_log "cmd output: $output\n" + +# There should be at least 6 lines probes +# Function entry, 4 actual source lines and function exit. +set output_lines [split $output "\n"] +set lines [llength $output_lines] +if { $lines >= 6 } { + pass "$test-run-one" +} else { + fail "$test-run-one ($lines)" +} + +# Expect the same output for next runs +set ::result_string $output + +# Sanity check, just run again... +stap_run3 $test-run-two $testpath/$test.stp -c $testexe + +# create a script based on the given statements, +# probe all of them individually. +set fp [open $test-run-statements.stp "w"] +foreach line $output_lines { + puts $fp "probe process(\"uprobe_stmt_num\").statement($line)" + puts $fp "{" + puts $fp " printf(\"0x%x\\n\", uaddr());" + puts $fp "}" +} +close $fp +stap_run3 $test-run-statements $test-run-statements.stp -c $testexe + +# Now strip away the line info and try again (with -g). +set strip_cmd [list "objcopy" "-R" ".debug_line"] +lappend strip_cmd "$testexe" +send_log "Executing: $strip_cmd\n" +eval exec $strip_cmd + +stap_run3 $test-run-statements-nolines -w -g $test-run-statements.stp -c $testexe + +# XXX Last test still fails. PR10454. +return + +# Now strip away all debuginfo. Since the script doesn't need any it +# should still work. +set strip_cmd [list "strip" "-g"] +lappend strip_cmd "$testexe" +send_log "Executing: $strip_cmd\n" +eval exec $strip_cmd + +stap_run3 $test-run-statements-nodebuginfo -w -g $test-run-statements.stp -c $testexe + +# cleanup +eval exec rm $testexe $test-run-statements.stp diff --git a/testsuite/systemtap.context/uprobe_stmt_num.stp b/testsuite/systemtap.context/uprobe_stmt_num.stp new file mode 100644 index 00000000..c2e8d5ba --- /dev/null +++ b/testsuite/systemtap.context/uprobe_stmt_num.stp @@ -0,0 +1,4 @@ +probe process("uprobe_stmt_num").statement("func@uprobe_stmt_num.c:*") +{ + printf("0x%x\n", uaddr()); +} diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp index 4f326ec1..9079cb40 100755..100644 --- a/testsuite/systemtap.examples/general/grapher.stp +++ b/testsuite/systemtap.examples/general/grapher.stp @@ -2,11 +2,13 @@ probe begin { -printf ("%%Title:CPU utilization\n"); -printf ("%%XAxisTitle:Time"); -printf ("%%YAxisTitle:Percent"); -printf ("%%DataSet:cpu 100 00ff00 bar"); -printf ("%%DataSet:kbd 100 ff0000 dot"); +printf ("%%DataSet:cpu 100 00ff00 bar\n"); +printf ("%%DataSet:kbd 75 ff0000 discreet\n"); +printf ("%%DataSet:pty 50 0000ff discreet\n"); +printf ("cpu %%Title:CPU utilization\n"); +printf ("cpu %%XAxisTitle:Time\n"); +printf ("cpu %%YAxisTitle:Percent\n"); + } # CPU utilization @@ -28,5 +30,14 @@ probe timer.ms(100) { # collect utilization percentages frequently } probe kernel.function("kbd_event") { - printf("kbd %d %d\n", gettimeofday_ms(), 75) + if ($event_type == 1 && $value) + printf("kbd %d %d\n", gettimeofday_ms(), $event_code) +} + +probe kernel.function("pty_write") { + if (count > 0) + printf("pty %d %.5s\n", gettimeofday_ms(), buf) } + + + diff --git a/testsuite/systemtap.exelib/ustack.tcl b/testsuite/systemtap.exelib/ustack.tcl index b70b8334..a670213a 100644 --- a/testsuite/systemtap.exelib/ustack.tcl +++ b/testsuite/systemtap.exelib/ustack.tcl @@ -1,12 +1,3 @@ -set ::result_string {exe: main=main -exe: main_func=main_func -exe: main_func=main_func -exe: main_func=main_func -lib: lib_main=lib_main -lib: lib_func=lib_func -lib: lib_func=lib_func - lib: lib_func=lib_func} - # Only run on make installcheck if {! [installtest_p]} { untested "ustack-$testname"; return } if {! [utrace_p]} { untested "ustack-$testname"; return } diff --git a/translate.cxx b/translate.cxx index ddd96938..4a6a10b5 100644 --- a/translate.cxx +++ b/translate.cxx @@ -3516,7 +3516,7 @@ c_unparser::visit_target_symbol (target_symbol* e) if (!e->probe_context_var.empty()) o->line() << "l->" << e->probe_context_var; else - throw semantic_error("cannot translate general cast expression", e->tok); + throw semantic_error("cannot translate general target expression", e->tok); } @@ -4780,7 +4780,7 @@ dump_unwindsyms (Dwfl_Module *m, // likely can't do anything about this; backtraces for the // affected module would just get all icky heuristicy. // So only report in verbose mode. - if (c->session.verbose > 2) + if (c->session.verbose > 2 && ! c->session.suppress_warnings) c->session.print_warning ("No unwind data for " + modname + ", " + dwfl_errmsg (-1)); } @@ -5081,12 +5081,12 @@ emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s) << ";\n"; // Some nonexistent modules may have been identified with "-d". Note them. - for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin(); - it != ctx->undone_unwindsym_modules.end(); - it ++) - { - s.print_warning ("missing unwind/symbol data for module '" + (*it) + "'"); - } + if (! s.suppress_warnings) + for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin(); + it != ctx->undone_unwindsym_modules.end(); + it ++) + s.print_warning ("missing unwind/symbol data for module '" + + (*it) + "'"); } @@ -16,6 +16,7 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "util.h" +#include "sys/sdt.h" #include <stdexcept> #include <cerrno> @@ -327,12 +328,14 @@ static pid_t spawned_pid = 0; int stap_system(const char *command) { + STAP_PROBE1(stap, stap_system__start, command); const char * argv[] = { "sh", "-c", command, NULL }; int ret, status; spawned_pid = 0; ret = posix_spawn(&spawned_pid, "/bin/sh", NULL, NULL, const_cast<char **>(argv), environ); + STAP_PROBE2(stap, stap_system__spawn, ret, spawned_pid); if (ret == 0) { if (waitpid(spawned_pid, &status, 0) == spawned_pid) @@ -340,6 +343,7 @@ stap_system(const char *command) else ret = errno; } + STAP_PROBE1(stap, stap_system__complete, ret); spawned_pid = 0; return ret; } |