diff options
author | Dave Brolley <brolley@redhat.com> | 2008-09-08 10:50:28 -0400 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2008-09-08 10:50:28 -0400 |
commit | e27cf4ed7ebf115a03fc29a639b72b983f5ddff2 (patch) | |
tree | b07abb50bcb5c03e4d88af1b00ae0edc8223091c | |
parent | 0bda97400ce6610899b3fbd7fd19f67030fedcc8 (diff) | |
parent | e6342ff8c11bbed1d2058507b918cf3c140e1322 (diff) | |
download | systemtap-steved-e27cf4ed7ebf115a03fc29a639b72b983f5ddff2.tar.gz systemtap-steved-e27cf4ed7ebf115a03fc29a639b72b983f5ddff2.tar.xz systemtap-steved-e27cf4ed7ebf115a03fc29a639b72b983f5ddff2.zip |
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
30 files changed, 973 insertions, 983 deletions
@@ -1,8 +1,26 @@ +2008-09-07 Frank Ch. Eigler <fche@elastic.org> + + * tapsets.cxx (build_blacklist): Add some x86 raw port-io spots. + +2008-09-06 Frank Ch. Eigler <fche@elastic.org> + + * tapsets.cxx (utrace_derived_probe ctor): Handle + process.* probe point reverse engineering (pid- and path-less). + +2008-09-05 Stan Cox <scox@redhat.com> + + * elaborate.cxx (add_global_var_display): Handle scalar statistics. + +2008-09-05 Frank Ch. Eigler <fche@elastic.org> + + * configure.ac, Makefile.am, systemtap.spec: Don't look for libcap. + * configure, Makefile.in: Regenerated. + 2008-09-05 Wenji Huang <wenji.huang@oracle.com> - PR 6731. - * main.cxx (usage,main,printscript): Improve listing mode with "-L". - * stap.1.in, stapex.5.in: Document it. + PR 6731. + * main.cxx (usage,main,printscript): Improve listing mode with "-L". + * stap.1.in, stapex.5.in: Document it. 2008-09-04 Frank Ch. Eigler <fche@elastic.org> diff --git a/Makefile.am b/Makefile.am index fe0fc408..c1bcd11e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,6 +68,8 @@ staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ stapio_CPPFLAGS = $(AM_CPPFLAGS) stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ + +PHONIES = if BUILD_ELFUTILS stap_CPPFLAGS += -Iinclude-elfutils stap_LDFLAGS += -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ @@ -85,7 +87,7 @@ stamp-elfutils: config.status stap_DEPENDENCIES = lib-elfutils/libdw.so lib-elfutils/libdw.so: stamp-elfutils ; -.PHONY: install-elfutils +PHONIES += install-elfutils install-elfutils: mkdir -p $(DESTDIR)$(pkglibdir) for file in lib-elfutils/*.so* lib-elfutils/${PACKAGE_NAME}/*.so*; do \ @@ -95,12 +97,11 @@ install-exec-local: install-elfutils endif staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ - runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c + runtime/staprun/ctl.c runtime/staprun/common.c staprun_CPPFLAGS = $(AM_CPPFLAGS) staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ +staprun_LDADD = @PROCFLAGS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ @@ -234,7 +235,10 @@ installcheck: # --define "with_bundled_elfutils 1" --define "elfutils_version 0.135" RPMBUILDFLAGS= -.PHONY: dist-gzip +PHONIES += dist-gzip + +.PHONY: $(PHONIES) + dist-gzip: cd $(srcdir); git status | grep working.directory.clean || (echo "You should commit your changes before 'make rpm'.") (cd $(srcdir); git archive --prefix=systemtap-$(VERSION)/ --format=tar HEAD) | gzip > systemtap-$(VERSION).tar.gz diff --git a/Makefile.in b/Makefile.in index ebd158dc..ff10a31d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -41,6 +41,7 @@ bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT) @BUILD_ELFUTILS_TRUE@am__append_3 = stamp-elfutils @BUILD_ELFUTILS_TRUE@am__append_4 = stamp-elfutils @BUILD_ELFUTILS_FALSE@stap_DEPENDENCIES = +@BUILD_ELFUTILS_TRUE@am__append_5 = install-elfutils pkglibexec_PROGRAMS = stapio$(EXEEXT) noinst_PROGRAMS = loc2c-test$(EXEEXT) subdir = . @@ -111,7 +112,7 @@ stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(stapio_LDFLAGS) \ $(LDFLAGS) -o $@ am_staprun_OBJECTS = staprun-staprun.$(OBJEXT) \ staprun-staprun_funcs.$(OBJEXT) staprun-ctl.$(OBJEXT) \ - staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT) + staprun-common.$(OBJEXT) staprun_OBJECTS = $(am_staprun_OBJECTS) staprun_DEPENDENCIES = staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(staprun_LDFLAGS) \ @@ -217,7 +218,6 @@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ -cap_LIBS = @cap_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ @@ -286,14 +286,14 @@ stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_2) staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ stapio_CPPFLAGS = $(AM_CPPFLAGS) stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ +PHONIES = $(am__append_5) dist-gzip @BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\ - runtime/staprun/ctl.c runtime/staprun/common.c \ - runtime/staprun/cap.c + runtime/staprun/ctl.c runtime/staprun/common.c staprun_CPPFLAGS = $(AM_CPPFLAGS) staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED -staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ +staprun_LDADD = @PROCFLAGS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ runtime/staprun/ctl.c \ @@ -523,7 +523,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay_old.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-stapio.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-cap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-ctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun.Po@am__quote@ @@ -739,20 +738,6 @@ staprun-common.obj: runtime/staprun/common.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi` -staprun-cap.o: runtime/staprun/cap.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-cap.o -MD -MP -MF $(DEPDIR)/staprun-cap.Tpo -c -o staprun-cap.o `test -f 'runtime/staprun/cap.c' || echo '$(srcdir)/'`runtime/staprun/cap.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-cap.Tpo $(DEPDIR)/staprun-cap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/cap.c' object='staprun-cap.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.o `test -f 'runtime/staprun/cap.c' || echo '$(srcdir)/'`runtime/staprun/cap.c - -staprun-cap.obj: runtime/staprun/cap.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-cap.obj -MD -MP -MF $(DEPDIR)/staprun-cap.Tpo -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-cap.Tpo $(DEPDIR)/staprun-cap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/cap.c' object='staprun-cap.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi` - .cxx.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @@ -1358,8 +1343,6 @@ cscope: @BUILD_ELFUTILS_TRUE@ done @BUILD_ELFUTILS_TRUE@ touch $@ @BUILD_ELFUTILS_TRUE@lib-elfutils/libdw.so: stamp-elfutils ; - -@BUILD_ELFUTILS_TRUE@.PHONY: install-elfutils @BUILD_ELFUTILS_TRUE@install-elfutils: @BUILD_ELFUTILS_TRUE@ mkdir -p $(DESTDIR)$(pkglibdir) @BUILD_ELFUTILS_TRUE@ for file in lib-elfutils/*.so* lib-elfutils/${PACKAGE_NAME}/*.so*; do \ @@ -1456,7 +1439,8 @@ installcheck: fi; $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" -.PHONY: dist-gzip +.PHONY: $(PHONIES) + dist-gzip: cd $(srcdir); git status | grep working.directory.clean || (echo "You should commit your changes before 'make rpm'.") (cd $(srcdir); git archive --prefix=systemtap-$(VERSION)/ --format=tar HEAD) | gzip > systemtap-$(VERSION).tar.gz @@ -1,5 +1,17 @@ * What's new +- Target process mode (stap -c CMD or -x PID) now implicitly restricts all + "process.*" probes to the given child process. (It does not effect + kernel.* or other probe types.) The CMD string is now executed directly, + rather than via a /bin/sh -c subshell. + + % stap -e 'probe process.syscall, process.end { + printf("%s %d %s\n", execname(), pid(), pp())}'\ + -c ls + ls 2323 process.syscall + ls 2323 process.syscall + ls 2323 process.end + - Probe listing mode is improved: "-L" lists available script-level variables % stap -L 'syscall.*open*' @@ -722,7 +722,6 @@ elfutils_abs_srcdir stap_LIBS DATE PROCFLAGS -cap_LIBS CXXCPP subdirs LIBOBJS @@ -6426,156 +6425,6 @@ else fi - -for ac_header in sys/capability.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## ------------------------------------------- ## -## Report this to systemtap@sources.redhat.com ## -## ------------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -else - { { echo "$as_me:$LINENO: error: cannot find required libcap header (libcap-devel may need to be installed)" >&5 -echo "$as_me: error: cannot find required libcap header (libcap-devel may need to be installed)" >&2;} - { (exit 1); exit 1; }; } -fi - -done - - build_elfutils=no # Check whether --with-elfutils was given. @@ -6717,90 +6566,6 @@ x86_64) PROCFLAGS=-m64 ;; esac -# -lcap is used for staprun, so PROCFLAGS comes in to play -SAVE_LIBS="$LIBS" -SAVE_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $PROCFLAGS" - -{ echo "$as_me:$LINENO: checking for cap_init in -lcap" >&5 -echo $ECHO_N "checking for cap_init in -lcap... $ECHO_C" >&6; } -if test "${ac_cv_lib_cap_cap_init+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcap $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char cap_init (); -int -main () -{ -return cap_init (); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - ac_cv_lib_cap_cap_init=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_cap_cap_init=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_init" >&5 -echo "${ECHO_T}$ac_cv_lib_cap_cap_init" >&6; } -if test $ac_cv_lib_cap_cap_init = yes; then - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBCAP 1 -_ACEOF - - LIBS="-lcap $LIBS" - -else - { { echo "$as_me:$LINENO: error: need $PROCFLAGS -lcap" >&5 -echo "$as_me: error: need $PROCFLAGS -lcap" >&2;} - { (exit 1); exit 1; }; } -fi - -cap_LIBS="$LIBS" - -LIBS="$SAVE_LIBS" -CFLAGS="$SAVE_CFLAGS" - # Use tr1/unordered_map if available ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -8048,14 +7813,13 @@ elfutils_abs_srcdir!$elfutils_abs_srcdir$ac_delim stap_LIBS!$stap_LIBS$ac_delim DATE!$DATE$ac_delim PROCFLAGS!$PROCFLAGS$ac_delim -cap_LIBS!$cap_LIBS$ac_delim CXXCPP!$CXXCPP$ac_delim subdirs!$subdirs$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 16; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/configure.ac b/configure.ac index 123ac657..294fabe1 100644 --- a/configure.ac +++ b/configure.ac @@ -161,9 +161,6 @@ if test "$enable_docs" == "yes"; then fi AM_CONDITIONAL([BUILD_DOCS], [test "x${have_latex}${have_dvips}${have_ps2pdf}${have_latex2html}" == "xyesyesyesyes" -a "$enable_docs" != "no"]) -AC_CHECK_HEADERS([sys/capability.h], , - [AC_MSG_ERROR([cannot find required libcap header (libcap-devel may need to be installed)])]) - dnl Handle elfutils. If '--with-elfutils=DIR' wasn't specified, used dnl the system's elfutils. build_elfutils=no @@ -215,16 +212,6 @@ x86_64) PROCFLAGS=-m64 ;; esac AC_SUBST([PROCFLAGS]) -# -lcap is used for staprun, so PROCFLAGS comes in to play -SAVE_LIBS="$LIBS" -SAVE_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $PROCFLAGS" -AC_CHECK_LIB(cap, cap_init, [], [AC_MSG_ERROR(need $PROCFLAGS -lcap)]) -cap_LIBS="$LIBS" -AC_SUBST(cap_LIBS) -LIBS="$SAVE_LIBS" -CFLAGS="$SAVE_CFLAGS" - # Use tr1/unordered_map if available AC_LANG_PUSH(C++) AC_CHECK_HEADERS([tr1/unordered_map]) diff --git a/doc/Makefile.in b/doc/Makefile.in index 47b6d85b..aed03ee2 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -111,7 +111,6 @@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ -cap_LIBS = @cap_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ diff --git a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml index 9285d0ae..f60ab2f3 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml @@ -5,15 +5,36 @@ <chapter id="introduction"> <title>Introduction</title> <para> - A short introduction on SystemTap_Beginners_Guide + SystemTap is a tracing and probing tool that provides users deep technical insight into what the operating system (particularly, the kernel) is doing at any given time. It provides information similar to the output of tools like <command>netstat</command>, <command>ps</command>, <command>top</command>, and <command>iostat</command>; however, SystemTap is designed to provide information that is more "granular" in nature. </para> -<formalpara> + <para> + For system administrators, SystemTap can be used as a performance monitoring tool for &PROD;. It is most useful when other similar tools cannot precisely pinpoint a bottleneck in the system, requiring a deep analysis of kernel activity. In the same manner, application developers can also use SystemTap to monitor, in finer detail, how their application behaves. + </para> + +<!-- + <para> + SystemTap was developed as a Linux version of the DTrace tool (for <trademark>Sun Solaris</trademark>). + </para> + --> +<section id="goals"> <title>Goals</title> - <para>TBD</para> -</formalpara> + <para>The goal of SystemTap is to provide infrastructure to monitor the running Linux kernel for detailed analysis. This can assist in identifying the underlying cause of a performance or functional problem.</para> + + <para>Without SystemTap, monitoring the activity of a running kernel would require a tedious instrument, recompile, install, and reboot sequence. SystemTap is designed to eliminate this, allowing you to gather the same information by simply running its suite of tools against specific <firstterm>tapsets</firstterm> or SystemTap scripts.</para> + + <para>However, SystemTap was initially designed for users with intermediate to advanced knowledge of the kernel. This could present a steep learning curve for administrators or developers whose knowledge of the Linux kernel is little to none.</para> + + <para>In line with that, the main goal of the <citetitle>SystemTap Beginner's Guide</citetitle> is two-fold:</para> + + <itemizedlist> + <listitem><para>To introduce users to SystemTap, familiarize them with its architecture, and provide setup instructions for all kernel types.</para></listitem> + + <listitem><para>To provide pre-written SystemTap scripts for monitoring and forensic tasks, along with instructions on how to analyze their output.</para></listitem> + </itemizedlist> +<!-- </formalpara> --> <remark>above, Short description on the underlying goals of SystemTap_Beginners_Guide, what we want to teach users.</remark> - +</section> <section id="intro-usage"> <title>Usage</title> @@ -25,7 +46,7 @@ <section id="intro-systemtap-vs-others"> <title>SystemTap Versus Other Monitoring Tools</title> <remark> - Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) + ** Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) </remark> <formalpara> diff --git a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent index 46bb6c06..994cf1a4 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent +++ b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent @@ -1,3 +1,4 @@ <!ENTITY PRODUCT "Red_Hat_Enterprise_Linux 5"> <!ENTITY BOOKID "SystemTap_Beginners_Guide"> -<!ENTITY YEAR "2009">
\ No newline at end of file +<!ENTITY YEAR "2009"> +<!ENTITY RHEL "Red Hat Enterprise Linux 5">
\ No newline at end of file diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index b3a1cbed..e418f561 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -8,18 +8,48 @@ Short summary; probes, handlers, events </remark> + <para>SystemTap allows users to write and reuse simple scripts to deeply examine the activities of a running Linux system. These scripts can be designed to extract data, filter it, and summarize it quickly (and safely), enabling the diagnosis of complex performance (or even functional) problems.</para> + + <para> The essential idea behind a SystemTap script is to name <emphasis>events</emphasis>, and to give them <emphasis>handlers</emphasis>. When SystemTap runs the script, SystemTap monitors for the event; once the event occurs, the Linux kernel then runs the handler as a quick sub-routine, then resumes.</para> + + <para>There are several kind of events; entering/exiting a function, timer expiration, session termination, etc. A handler is a series of script language statements that specify the work to be done whenever the event occurs. This work normally includes extracting data from the event context, storing them into internal variables, or printing results.</para> + <section id="understanding-architecture-tools"> <title>Architecture</title> <remark> - add diagram, describe architecture, enumerate common tools + ** add diagram, describe architecture, enumerate common tools </remark> - </section> + + <remark> + ** architecture diagram must be simpler, if at all included + </remark> + + <remark> + ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc" + </remark> + + <para>A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion:</para> + +<procedure> + <title>SystemTap Session</title> + <step><para>SystemTap first translates the script to C, running the system C compiler to create a kernel module from it.</para></step> + + <step><para>SystemTap then loads the module, then enables all the probed events by "hooking" those events into the kernel.</para></step> + + <step><para>As the events occur, their corresponding handlers are executed.</para></step> + + <step><para>Once the SystemTap session is terminated, the hooked events are disconnected from the kernel; afterwards, the kernel module is unloaded.</para></step> +</procedure> + +<para>This sequence is driver from a single command-line program: <command>stap</command>. This program is SystemTap's main front-end tool. For more information about <command>stap</command>, refer to <command>man stap</command> (once SystemTap is set up on your machine).</para> + +</section> <section id="understanding-scripts"> <title>SystemTap Scripts</title> <remark> - definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them) + ** definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them) </remark> </section> diff --git a/elaborate.cxx b/elaborate.cxx index 44b6e24f..3dfc7183 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1194,15 +1194,35 @@ void add_global_var_display (systemtap_session& s) if (l->index_types.size() == 0) // Scalar { - if (l->type == pe_string) + if (l->type == pe_stats) + pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n"; + else if (l->type == pe_string) pf->raw_components += "=\"%#s\"\\n"; else pf->raw_components += "=%#x\\n"; - pf->args.push_back(g_sym); pf->components = print_format::string_to_components(pf->raw_components); expr_statement* feb = new expr_statement; feb->value = pf; feb->tok = print_tok; + if (l->type == pe_stats) + { + struct stat_op* so [5]; + const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average}; + + for (unsigned si = 0; + si < (sizeof(so)/sizeof(struct stat_op*)); + si++) + { + so[si]= new stat_op; + so[si]->ctype = stypes[si]; + so[si]->type = pe_long; + so[si]->stat = g_sym; + so[si]->tok = l->tok; + pf->args.push_back(so[si]); + } + } + else + pf->args.push_back(g_sym); b->statements.push_back(feb); } else // Array @@ -1265,6 +1285,8 @@ void add_global_var_display (systemtap_session& s) { struct stat_op* so [5]; const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average}; + + ai->type = pe_stats; for (unsigned si = 0; si < (sizeof(so)/sizeof(struct stat_op*)); si++) @@ -1274,13 +1296,8 @@ void add_global_var_display (systemtap_session& s) so[si]->type = pe_long; so[si]->stat = ai; so[si]->tok = l->tok; + pf->args.push_back(so[si]); } - - ai->type = pe_stats; - for (unsigned si = 0; - si < (sizeof(so)/sizeof(struct stat_op*)); - si++) - pf->args.push_back(so[si]); } else pf->args.push_back(ai); diff --git a/runtime/ChangeLog b/runtime/ChangeLog index e02c5f0b..eb091d01 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,18 @@ +2008-09-08 Tim Moore <timoore@redhat.com> + + PR 1288 + * addr-map.c: New file with functions for looking up addresses + * loc2c-runtime.h (deref, store_deref): Use lookup_bad_addr to + avoid dereferencing known dangerous addresses. + * runtime.h: Include addr-map.c. + +2008-09-06 Frank Ch. Eigler <fche@elastic.org> + + PR 6445 + * task_finder.c (stap_start_task_finder): When _stp_target + is set (stap -c or -x mode), restrict initial utrace attach + iteration to target process only. + 2008-09-01 Frank Ch. Eigler <fche@elastic.org> * task_finder.c: Move CONFIG_UTRACE assertion here. diff --git a/runtime/addr-map.c b/runtime/addr-map.c new file mode 100644 index 00000000..8231b57f --- /dev/null +++ b/runtime/addr-map.c @@ -0,0 +1,181 @@ +/* -*- linux-c -*- + * Map of addresses to disallow. + * Copyright (C) 2005-2008 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. + */ + +#ifndef _ADDR_MAP_C_ +#define _ADDR_MAP_C_ 1 + +/** @file addr-map + * @brief Implements functions used by the deref macro to blacklist + * certain addresses. + */ + +struct addr_map_entry +{ + unsigned long min; + unsigned long max; +}; + +struct addr_map +{ + size_t size; + struct addr_map_entry entries[0]; +}; + +static DEFINE_SPINLOCK(addr_map_lock); + +struct addr_map* blackmap; + +/* Find address of entry where we can insert a new one. */ +static size_t +upper_bound(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end = map->size; + struct addr_map_entry *entry = 0; + + if (end == 0) + return 0; + do + { + size_t new_idx; + if (addr < map->entries[start].min) + return start; + if (addr >= map->entries[end-1].max) + return end; + new_idx = (end + start) / 2; + entry = &map->entries[new_idx]; + if (addr < entry->min) + end = new_idx; + else + start = new_idx + 1; + } while (end != start); + return entry - &map->entries[0]; +} + +static struct addr_map_entry* +lookup_addr_aux(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end; + if (!map) + return 0; + end = map->size; + if (map->size == 0) + return 0; + + do + { + int entry_idx; + struct addr_map_entry *entry = 0; + if (addr < map->entries[start].min || addr >= map->entries[end - 1].max) + return 0; + entry_idx = (end + start) / 2; + entry = &map->entries[entry_idx]; + if (entry->min <= addr && entry->max > addr) + return entry; + if (addr < entry->min) + end = entry_idx; + else + start = entry_idx + 1; + } while (start < end); + return 0; +} + +int +lookup_bad_addr(unsigned long addr) +{ + struct addr_map_entry* result = 0; + spin_lock(&addr_map_lock); + result = lookup_addr_aux(addr, blackmap); + spin_unlock(&addr_map_lock); + if (result) + return 1; + else + return 0; +} + + +int +add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, + struct addr_map_entry** existing_min, + struct addr_map_entry** existing_max) +{ + struct addr_map* new_map = 0; + struct addr_map* old_map = 0; + struct addr_map_entry* min_entry = 0; + struct addr_map_entry* max_entry = 0; + struct addr_map_entry* new_entry = 0; + size_t existing = 0; + + while (1) + { + size_t old_size; + spin_lock(&addr_map_lock); + old_map = blackmap; + if (!blackmap) + { + existing = 0; + old_size = 0; + } + else + { + min_entry = lookup_addr_aux(min_addr, blackmap); + max_entry = lookup_addr_aux(max_addr, blackmap); + if (min_entry || max_entry) + { + if (existing_min) + *existing_min = min_entry; + if (existing_max) + *existing_max = max_entry; + spin_unlock(&addr_map_lock); + return 1; + } + existing = upper_bound(min_addr, old_map); + old_size = old_map->size; + } + spin_unlock(&addr_map_lock); + new_map = kmalloc(sizeof(*new_map) + + sizeof(*new_entry) * (old_size + 1), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + spin_lock(&addr_map_lock); + if (blackmap != old_map) + { + kfree(new_map); + spin_unlock(&addr_map_lock); + continue; + } + new_entry = &new_map->entries[existing]; + new_entry->min = min_addr; + new_entry->max = max_addr; + if (old_map) + { + memcpy(&new_map->entries, old_map->entries, + existing * sizeof(*new_entry)); + if (old_map->size > existing) + memcpy(new_entry + 1, &old_map->entries[existing + 1], + (old_map->size - existing) * sizeof(*new_entry)); + } + new_map->size = blackmap->size + 1; + blackmap = new_map; + spin_unlock(&addr_map_lock); + if (old_map) + kfree(old_map); + return 0; + } +} + +void +delete_bad_addr_entry(struct addr_map_entry* entry) +{ +} + +#endif diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 1247da51..0af19edc 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -201,6 +201,8 @@ #define deref(size, addr) ({ \ intptr_t _i; \ + if (lookup_bad_addr((unsigned long)addr)) \ + __deref_bad(); \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ @@ -213,6 +215,8 @@ }) #define store_deref(size, addr, value) ({ \ + if (lookup_bad_addr((unsigned long)addr)) \ + __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ @@ -234,30 +238,36 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - default: _v = __get_user_bad(); \ - } \ - if (_bad) \ - DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - default: __put_user_bad(); \ - } \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break;\ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + default: __put_user_bad(); \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) @@ -268,14 +278,17 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -284,14 +297,17 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -301,13 +317,16 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __get_user_size(_v, addr, 1, _bad); break; \ - case 2: __get_user_size(_v, addr, 2, _bad); break; \ - case 4: __get_user_size(_v, addr, 4, _bad); break; \ - case 8: __get_user_size(_v, addr, 8, _bad); break; \ - default: __get_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __get_user_size(_v, addr, 1, _bad); break; \ + case 2: __get_user_size(_v, addr, 2, _bad); break; \ + case 4: __get_user_size(_v, addr, 4, _bad); break; \ + case 8: __get_user_size(_v, addr, 8, _bad); break; \ + default: __get_user_unknown(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -316,13 +335,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __put_user_size(value, addr, 1, _bad); break; \ - case 2: __put_user_size(value, addr, 2, _bad); break; \ - case 4: __put_user_size(value, addr, 4, _bad); break; \ - case 8: __put_user_size(value, addr, 8, _bad); break; \ - default: __put_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __put_user_size(value, addr, 1, _bad); break; \ + case 2: __put_user_size(value, addr, 2, _bad); break; \ + case 4: __put_user_size(value, addr, 4, _bad); break; \ + case 8: __put_user_size(value, addr, 8, _bad); break; \ + default: __put_user_unknown(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -373,30 +395,36 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ - case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ - case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ - case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ + case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ + case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ + case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ - DEREF_FAULT(addr); \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ - case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ - case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ - case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ + case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ + case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ + case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -541,12 +569,15 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ - case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ - case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ - default: __get_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ + case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ + case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ + default: __get_user_bad(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -555,13 +586,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ - case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ - case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ - case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ - default: __put_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ + case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ + case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ + case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ + default: __put_user_bad(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -624,28 +658,31 @@ extern void __store_deref_bad(void); u8 _b; u16 _w; u32 _l; u64 _q; \ int _bad = 0; \ intptr_t _v = 0; \ - switch (size) { \ - case 1: { \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) { \ + case 1: { \ __stp_get_asm(_b, addr, _bad, 1); \ _v = _b; \ break; \ - }; \ - case 2: { \ + }; \ + case 2: { \ __stp_get_asm(_w, addr, _bad, 2); \ _v = _w; \ break; \ - }; \ - case 4: { \ + }; \ + case 4: { \ __stp_get_asm(_l, addr, _bad, 4); \ _v = _l; \ break; \ - }; \ - case 8: { \ + }; \ + case 8: { \ __stp_get_asm(_q, addr, _bad, 8); \ _v = _q; \ break; \ - }; \ - default: \ + }; \ + default: \ _bad = -EFAULT; \ } \ if (_bad) \ @@ -657,12 +694,17 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ int i; \ - for(i=0;i<size;i++){ \ - __stp_put_asm((u8)(value>>((size-i-1)*8)&0xff), \ - (u64)addr+i,_bad); \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + for(i=0;i<size;i++){ \ + __stp_put_asm((u8)(value>>((size-i-1)*8)&0xff), \ + (u64)addr+i,_bad); \ + if (_bad) \ + break; \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) diff --git a/runtime/runtime.h b/runtime/runtime.h index 2711f531..fd0cac9e 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -88,6 +88,7 @@ static struct #ifdef STP_PERFMON #include "perf.c" #endif +#include "addr-map.c" /* Support functions for int64_t module parameters. */ int param_set_int64_t(const char *val, struct kernel_param *kp) diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index a4f47880..21e02e47 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,16 @@ +2008-09-06 Frank Ch. Eigler <fche@elastic.org> + + * mainloop.c (start_cmd): Rewrite to use wordexp/execvp/ptrace. + (stp_main_loop): Use ptrace detach to resume target process. + +2008-09-05 Frank Ch. Eigler <fche@elastic.org> + + * staprun.c (run_as): Teach it to exec too. Update callers. + Always do set[ug]id as dictated. + * staprun.h (do_cap): Remove. Update all callers. + * staprun_funcs.c: Ditto. + * cap.c: Removed. Update headers. + 2008-07-10 Frank Ch. Eigler <fche@elastic.org> PR 6736. diff --git a/runtime/staprun/cap.c b/runtime/staprun/cap.c deleted file mode 100644 index 6ac6701f..00000000 --- a/runtime/staprun/cap.c +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- linux-c -*- - * - * cap.c - staprun capabilities functions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2007 Red Hat, Inc. - * - */ - -#include "staprun.h" -#include <sys/prctl.h> - -static int _stp_no_caps = 0; - -/* like perror, but exits */ -#define ferror(msg) { \ - _perr(msg); \ - exit(1); \ - } \ - -/* - * init_cap() sets up the initial capabilities for staprun. Then - * it calls prctl( PR_SET_KEEPCAPS) to arrrange to keep these capabilities - * even when not running as root. Next it resets the real, effective, and - * saved uid and gid back to the normal user. - * - * There are two sets of capabilities we are concerned with; permitted - * and effective. The permitted capabilities are all the capabilities - * that this process is ever permitted to have. They are defined in init_cap() - * and may be permanently removed with drop_cap(). - * - * Effective capabilities are the capabilities from the permitted set - * that are currently enabled. A good practice would be to only enable - * capabilities when necessary and to delete or drop them as soon as possible. - * - * Capabilities we might use include: - * - * CAP_SYS_MODULE - insert and remove kernel modules - * CAP_SYS_ADMIN - misc, including mounting and unmounting - * CAP_SYS_NICE - setpriority() - * CAP_SETUID - allows setuid - * CAP_SETGID - allows setgid - * CAP_CHOWN - allows chown - */ - -void init_cap(void) -{ - cap_t caps = cap_init(); - cap_value_t capv[] = { CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE }; - const int numcaps = sizeof(capv) / sizeof(capv[0]); - uid_t uid = getuid(); - gid_t gid = getgid(); - - cap_clear(caps); - if (caps == NULL) - ferror("cap_init"); - - if (cap_set_flag(caps, CAP_PERMITTED, numcaps, capv, CAP_SET) < 0) - ferror("cap_set_flag"); - - if (cap_set_proc(caps) < 0) { - dbug(1, "Setting capabilities failed. Capabilities disabled.\n"); - _stp_no_caps = 1; - return; - } - - cap_free(caps); - - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) - ferror("prctl"); - - if (setresuid(uid, uid, uid) < 0) - ferror("setresuid"); - - if (setresgid(gid, gid, gid) < 0) - ferror("setresgid"); -} - -void print_cap(char *text) -{ - int p; - cap_t caps = cap_get_proc(); - uid_t uid, euid, suid; - gid_t gid, egid, sgid; - - if (caps == NULL) { - perr("cap_get_proc"); - return; - } - - getresuid(&uid, &euid, &suid); - getresgid(&gid, &egid, &sgid); - - printf("***** %s\n", text); - - if ((p = prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0) - perr("Couldn't get PR_SET_KEEPCAPS flag value"); - else - printf("KEEPCAPS: %d\n", p); - - printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n", uid, euid, suid, gid, egid, sgid); - printf("Caps: %s\n", cap_to_text(caps, NULL)); - cap_free(caps); - printf("*****\n\n"); -} - -/* drop_cap() permanently removes a capability from the permitted set. There is - * no way to recover the capability after this. You do not need to remove - * it from the effective set before calling this. - */ -void drop_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0) - ferror("Could not clear effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} - -/* add_cap() adds a permitted capability to the effective set. */ -void add_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0) - ferror("Could not set effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} - -/* del_cap() deletes a permitted capability from the effective set. */ -void del_cap(cap_value_t cap) -{ - if (_stp_no_caps == 0) { - cap_t caps = cap_get_proc(); - if (caps == NULL) - ferror("cap_get_proc failed"); - if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0) - ferror("Could not clear effective capabilities"); - if (cap_set_proc(caps) < 0) - ferror("Could not apply capability set"); - cap_free(caps); - } -} diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index a7b919cb..6fc061ae 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -12,6 +12,9 @@ #include "staprun.h" #include <sys/utsname.h> +#include <sys/ptrace.h> +#include <wordexp.h> + /* globals */ int ncpus; @@ -22,172 +25,192 @@ static int use_old_transport = 0; static void *signal_thread(void *arg) { - sigset_t *s = (sigset_t *) arg; - int signum, rc, btype = STP_EXIT; - - while (1) { - if (sigwait(s, &signum) < 0) { - _perr("sigwait"); - continue; - } - dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum)); - if (signum == SIGQUIT) - cleanup_and_exit(1); - else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) { - // send STP_EXIT - rc = write(control_channel, &btype, sizeof(btype)); - break; - } - } - return NULL; + sigset_t *s = (sigset_t *) arg; + int signum, rc, btype = STP_EXIT; + + while (1) { + if (sigwait(s, &signum) < 0) { + _perr("sigwait"); + continue; + } + dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum)); + if (signum == SIGQUIT) + cleanup_and_exit(1); + else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) { + // send STP_EXIT + rc = write(control_channel, &btype, sizeof(btype)); + break; + } + } + return NULL; } static void chld_proc(int signum) { - int32_t rc, btype = STP_EXIT; - dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum)); - pid_t pid = waitpid(-1, NULL, WNOHANG); - if (pid != target_pid) - return; - // send STP_EXIT - rc = write(control_channel, &btype, sizeof(btype)); + int32_t rc, btype = STP_EXIT; + dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum)); + pid_t pid = waitpid(-1, NULL, WNOHANG); + if (pid != target_pid) + return; + // send STP_EXIT + rc = write(control_channel, &btype, sizeof(btype)); } static void setup_main_signals(void) { - pthread_t tid; - struct sigaction sa; - sigset_t *s = malloc(sizeof(*s)); - if (!s) { - _perr("malloc failed"); - exit(1); - } - sigfillset(s); - pthread_sigmask(SIG_SETMASK, s, NULL); - memset(&sa, 0, sizeof(sa)); - sigfillset(&sa.sa_mask); - sa.sa_handler = SIG_IGN; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - - sa.sa_handler = chld_proc; - sigaction(SIGCHLD, &sa, NULL); - - sigemptyset(s); - sigaddset(s, SIGINT); - sigaddset(s, SIGTERM); - sigaddset(s, SIGHUP); - sigaddset(s, SIGQUIT); - pthread_sigmask(SIG_SETMASK, s, NULL); - if (pthread_create(&tid, NULL, signal_thread, s) < 0) { - _perr("failed to create thread"); - exit(1); - } + pthread_t tid; + struct sigaction sa; + sigset_t *s = malloc(sizeof(*s)); + if (!s) { + _perr("malloc failed"); + exit(1); + } + sigfillset(s); + pthread_sigmask(SIG_SETMASK, s, NULL); + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + + sa.sa_handler = chld_proc; + sigaction(SIGCHLD, &sa, NULL); + + sigemptyset(s); + sigaddset(s, SIGINT); + sigaddset(s, SIGTERM); + sigaddset(s, SIGHUP); + sigaddset(s, SIGQUIT); + pthread_sigmask(SIG_SETMASK, s, NULL); + if (pthread_create(&tid, NULL, signal_thread, s) < 0) { + _perr("failed to create thread"); + exit(1); + } } -/* - * start_cmd forks the command given on the command line - * with the "-c" option. It will not exec that command - * until it received signal SIGUSR1. We do it this way because - * we must have the pid of the forked command so it can be set to - * the module and made available internally as _stp_target. - * SIGUSR1 is sent from stp_main_loop() below when it receives - * STP_START from the module. +/* + * start_cmd forks the command given on the command line with the "-c" + * option. It will wait just at the cusp of the exec until we get the + * signal from the kernel to let it run. We do it this way because we + * must have the pid of the forked command so it can be set to the + * module and made available internally as _stp_target. PTRACE_DETACH + * is sent from stp_main_loop() below when it receives STP_START from + * the module. */ void start_cmd(void) { - pid_t pid; - sigset_t usrset; - struct sigaction a; - - sigemptyset(&usrset); - sigaddset(&usrset, SIGUSR1); - pthread_sigmask(SIG_BLOCK, &usrset, NULL); - - /* if we are execing a target cmd, ignore ^C in stapio */ - /* and let the target cmd get it. */ - sigemptyset(&a.sa_mask); - a.sa_flags = 0; - a.sa_handler = SIG_IGN; - sigaction(SIGINT, &a, NULL); - - dbug(1, "execing target_cmd %s\n", target_cmd); - if ((pid = fork()) < 0) { - _perr("fork"); - exit(1); - } else if (pid == 0) { - int signum; - - a.sa_handler = SIG_DFL; - sigaction(SIGINT, &a, NULL); - - /* commands we fork need to run at normal priority */ - setpriority(PRIO_PROCESS, 0, 0); - - /* wait here until signaled */ - sigwait(&usrset, &signum); - - if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) - perror(target_cmd); - _exit(1); - } - target_pid = pid; + pid_t pid; + struct sigaction a; + + /* if we are execing a target cmd, ignore ^C in stapio */ + /* and let the target cmd get it. */ + sigemptyset(&a.sa_mask); + a.sa_flags = 0; + a.sa_handler = SIG_IGN; + sigaction(SIGINT, &a, NULL); + + if ((pid = fork()) < 0) { + _perr("fork"); + exit(1); + } else if (pid == 0) { + /* We're in the target process. Let's start the execve of target_cmd, */ + int rc; + wordexp_t words; + + a.sa_handler = SIG_DFL; + sigaction(SIGINT, &a, NULL); + + /* Formerly, we just execl'd(sh,-c,$target_cmd). But this does't + work well if target_cmd is a shell builtin. We really want to + probe a new child process, not a mishmash of shell-interpreted + stuff. */ + rc = wordexp (target_cmd, & words, WRDE_NOCMD); + if (rc != 0) { _perr ("wordexp parsing error"); _exit (1); } + if (words.we_wordc < 1) { _perr ("empty target_cmd"); _exit (1); } + + rc = ptrace (PTRACE_TRACEME, 0, 0, 0); + if (rc < 0) perror ("ptrace me"); + +#if 0 + dbug(1, "blocking briefly\n"); + raise (SIGCONT); /* Harmless; just passes control to parent. */ +#endif + + dbug(1, "execing target_cmd %s\n", target_cmd); + + /* Note that execvp() is not a direct system call; it does a $PATH + search in glibc. We would like to filter out these dummy syscalls + from the utrace events seen by scripts. */ + if (execvp (words.we_wordv[0], words.we_wordv) < 0) + perror(target_cmd); + + /* (There is no need to wordfree() words; they are or will be gone.) */ + + _exit(1); + } else { + /* We're in the parent. The child will parse target_cmd and execv() + the result. It will be stopped thereabouts and send us a SIGTRAP. */ + target_pid = pid; + int status; + waitpid (target_pid, &status, 0); + dbug(1, "waited for target_cmd %s pid %d status %x\n", target_cmd, target_pid, (unsigned) status); + } } -/** +/** * system_cmd() executes system commands in response * to an STP_SYSTEM message from the module. These * messages are sent by the system() systemtap function. */ void system_cmd(char *cmd) { - pid_t pid; - - dbug(2, "system %s\n", cmd); - if ((pid = fork()) < 0) { - _perr("fork"); - } else if (pid == 0) { - setpriority(PRIO_PROCESS, 0, 0); - if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) - perr("%s", cmd); - _exit(1); - } + pid_t pid; + + dbug(2, "system %s\n", cmd); + if ((pid = fork()) < 0) { + _perr("fork"); + } else if (pid == 0) { + setpriority(PRIO_PROCESS, 0, 0); + if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) + perr("%s", cmd); + _exit(1); + } } /* This is only used in the old relayfs code */ static void read_buffer_info(void) { - char buf[PATH_MAX]; - struct statfs st; - int fd, len, ret; - - if (!use_old_transport) - return; - - if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) - return; - - if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) - return; - fd = open(buf, O_RDONLY); - if (fd < 0) - return; - - len = read(fd, buf, sizeof(buf)); - if (len <= 0) { - perr("Couldn't read bufsize"); - close(fd); - return; - } - ret = sscanf(buf, "%u,%u", &n_subbufs, &subbuf_size); - if (ret != 2) - perr("Couldn't read bufsize"); - - dbug(2, "n_subbufs= %u, size=%u\n", n_subbufs, subbuf_size); - close(fd); - return; + char buf[PATH_MAX]; + struct statfs st; + int fd, len, ret; + + if (!use_old_transport) + return; + + if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) + return; + + if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname)) + return; + fd = open(buf, O_RDONLY); + if (fd < 0) + return; + + len = read(fd, buf, sizeof(buf)); + if (len <= 0) { + perr("Couldn't read bufsize"); + close(fd); + return; + } + ret = sscanf(buf, "%u,%u", &n_subbufs, &subbuf_size); + if (ret != 2) + perr("Couldn't read bufsize"); + + dbug(2, "n_subbufs= %u, size=%u\n", n_subbufs, subbuf_size); + close(fd); + return; } /** @@ -198,79 +221,79 @@ static void read_buffer_info(void) */ int init_stapio(void) { - dbug(2, "init_stapio\n"); - - /* create control channel */ - use_old_transport = init_ctl_channel(modname, 1); - if (use_old_transport < 0) { - err("Failed to initialize control channel.\n"); - return -1; - } - read_buffer_info(); - - if (attach_mod) { - dbug(2, "Attaching\n"); - if (use_old_transport) { - if (init_oldrelayfs() < 0) { - close_ctl_channel(); - return -1; - } - } else { - if (init_relayfs() < 0) { - close_ctl_channel(); - return -1; - } - } - return 0; - } - - /* fork target_cmd if requested. */ - /* It will not actually exec until signalled. */ - if (target_cmd) - start_cmd(); - - return 0; + dbug(2, "init_stapio\n"); + + /* create control channel */ + use_old_transport = init_ctl_channel(modname, 1); + if (use_old_transport < 0) { + err("Failed to initialize control channel.\n"); + return -1; + } + read_buffer_info(); + + if (attach_mod) { + dbug(2, "Attaching\n"); + if (use_old_transport) { + if (init_oldrelayfs() < 0) { + close_ctl_channel(); + return -1; + } + } else { + if (init_relayfs() < 0) { + close_ctl_channel(); + return -1; + } + } + return 0; + } + + /* fork target_cmd if requested. */ + /* It will not actually exec until signalled. */ + if (target_cmd) + start_cmd(); + + return 0; } /* cleanup_and_exit() closed channels, frees memory, * removes the module (if necessary) and exits. */ void cleanup_and_exit(int detach) { - pid_t err; - static int exiting = 0; - - if (exiting) - return; - exiting = 1; - - setup_main_signals(); - - dbug(1, "detach=%d\n", detach); - - /* what about child processes? we will wait for them here. */ - err = waitpid(-1, NULL, WNOHANG); - if (err >= 0) - err("\nWaiting for processes to exit\n"); - while (wait(NULL) > 0) ; - - if (use_old_transport) - close_oldrelayfs(detach); - else - close_relayfs(); - - dbug(1, "closing control channel\n"); - close_ctl_channel(); - - if (detach) { - err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname); - } else { - dbug(2, "removing %s\n", modname); - if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) { - perror(modname); - _exit(1); - } - } - _exit(0); + pid_t err; + static int exiting = 0; + + if (exiting) + return; + exiting = 1; + + setup_main_signals(); + + dbug(1, "detach=%d\n", detach); + + /* what about child processes? we will wait for them here. */ + err = waitpid(-1, NULL, WNOHANG); + if (err >= 0) + err("\nWaiting for processes to exit\n"); + while (wait(NULL) > 0) ; + + if (use_old_transport) + close_oldrelayfs(detach); + else + close_relayfs(); + + dbug(1, "closing control channel\n"); + close_ctl_channel(); + + if (detach) { + err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname); + } else { + dbug(2, "removing %s\n", modname); + if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) { + perror(modname); + _exit(1); + } + } + _exit(0); } /** @@ -279,97 +302,106 @@ void cleanup_and_exit(int detach) int stp_main_loop(void) { - ssize_t nb; - void *data; - uint32_t type; - FILE *ofp = stdout; - char recvbuf[8196]; - - setvbuf(ofp, (char *)NULL, _IOLBF, 0); - setup_main_signals(); - dbug(2, "in main loop\n"); - - send_request(STP_READY, NULL, 0); - - /* handle messages from control channel */ - while (1) { - nb = read(control_channel, recvbuf, sizeof(recvbuf)); - dbug(2, "nb=%d\n", (int)nb); - if (nb <= 0) { - if (errno != EINTR) - _perr("Unexpected EOF in read (nb=%ld)", (long)nb); - continue; - } - - type = *(uint32_t *) recvbuf; - data = (void *)(recvbuf + sizeof(uint32_t)); - nb -= sizeof(uint32_t); - - switch (type) { + ssize_t nb; + void *data; + uint32_t type; + FILE *ofp = stdout; + char recvbuf[8196]; + + setvbuf(ofp, (char *)NULL, _IOLBF, 0); + setup_main_signals(); + dbug(2, "in main loop\n"); + + send_request(STP_READY, NULL, 0); + + /* handle messages from control channel */ + while (1) { + nb = read(control_channel, recvbuf, sizeof(recvbuf)); + dbug(2, "nb=%d\n", (int)nb); + if (nb <= 0) { + if (errno != EINTR) + _perr("Unexpected EOF in read (nb=%ld)", (long)nb); + continue; + } + + type = *(uint32_t *) recvbuf; + data = (void *)(recvbuf + sizeof(uint32_t)); + nb -= sizeof(uint32_t); + + switch (type) { #ifdef STP_OLD_TRANSPORT - case STP_REALTIME_DATA: - { - ssize_t bw = write(out_fd[0], data, nb); - if (bw >= 0 && bw != nb) { - nb = nb - bw; - bw = write(out_fd[0], data, nb); - } - if (bw != nb) { - _perr("write error (nb=%ld)", (long)nb); - cleanup_and_exit(0); - } - break; - } + case STP_REALTIME_DATA: + { + ssize_t bw = write(out_fd[0], data, nb); + if (bw >= 0 && bw != nb) { + nb = nb - bw; + bw = write(out_fd[0], data, nb); + } + if (bw != nb) { + _perr("write error (nb=%ld)", (long)nb); + cleanup_and_exit(0); + } + break; + } #endif - case STP_OOB_DATA: - fputs((char *)data, stderr); - break; - case STP_EXIT: - { - /* module asks us to unload it and exit */ - dbug(2, "got STP_EXIT\n"); - cleanup_and_exit(0); - break; - } - case STP_START: - { - struct _stp_msg_start *t = (struct _stp_msg_start *)data; - dbug(2, "probe_start() returned %d\n", t->res); - if (t->res < 0) { - if (target_cmd) - kill(target_pid, SIGKILL); - cleanup_and_exit(0); - } else if (target_cmd) - kill(target_pid, SIGUSR1); - break; - } - case STP_SYSTEM: - { - struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; - dbug(2, "STP_SYSTEM: %s\n", c->cmd); - system_cmd(c->cmd); - break; - } - case STP_TRANSPORT: - { - struct _stp_msg_start ts; - if (use_old_transport) { - if (init_oldrelayfs() < 0) - cleanup_and_exit(0); - } else { - if (init_relayfs() < 0) - cleanup_and_exit(0); - } - ts.target = target_pid; - send_request(STP_START, &ts, sizeof(ts)); - if (load_only) - cleanup_and_exit(1); - break; - } - default: - err("WARNING: ignored message of type %d\n", (type)); - } - } - fclose(ofp); - return 0; + case STP_OOB_DATA: + fputs((char *)data, stderr); + break; + case STP_EXIT: + { + /* module asks us to unload it and exit */ + dbug(2, "got STP_EXIT\n"); + cleanup_and_exit(0); + break; + } + case STP_START: + { + struct _stp_msg_start *t = (struct _stp_msg_start *)data; + dbug(2, "probe_start() returned %d\n", t->res); + if (t->res < 0) { + if (target_cmd) + kill(target_pid, SIGKILL); + cleanup_and_exit(0); + } else if (target_cmd) { + dbug(1, "detaching pid %d\n", target_pid); + int rc = ptrace (PTRACE_DETACH, target_pid, 0, 0); + if (rc < 0) + { + perror ("ptrace detach"); + if (target_cmd) + kill(target_pid, SIGKILL); + cleanup_and_exit(0); + } + } + break; + } + case STP_SYSTEM: + { + struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; + dbug(2, "STP_SYSTEM: %s\n", c->cmd); + system_cmd(c->cmd); + break; + } + case STP_TRANSPORT: + { + struct _stp_msg_start ts; + if (use_old_transport) { + if (init_oldrelayfs() < 0) + cleanup_and_exit(0); + } else { + if (init_relayfs() < 0) + cleanup_and_exit(0); + } + ts.target = target_pid; + send_request(STP_START, &ts, sizeof(ts)); + if (load_only) + cleanup_and_exit(1); + break; + } + default: + err("WARNING: ignored message of type %d\n", (type)); + } + } + fclose(ofp); + return 0; } diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c index 664b75ee..f8a08876 100644 --- a/runtime/staprun/staprun.c +++ b/runtime/staprun/staprun.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * - * staprun.c - SystemTap module loader + * staprun.c - SystemTap module loader * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,14 +34,14 @@ extern long delete_module(const char *, unsigned int); int send_relocations (); -static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[]) +static int run_as(int exec_p, uid_t uid, gid_t gid, const char *path, char *const argv[]) { pid_t pid; int rstatus; if (verbose >= 2) { int i = 0; - err("execing: "); + err(exec_p ? "execing: ": "spawning: "); while (argv[i]) { err("%s ", argv[i]); i++; @@ -49,36 +49,43 @@ static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[]) err("\n"); } - if ((pid = fork()) < 0) { - _perr("fork"); - return -1; - } else if (pid == 0) { - /* Make sure we run as the full user. If we're - * switching to a non-root user, this won't allow - * that process to switch back to root (since the - * original process is setuid). */ - if (uid != getuid()) { - if (do_cap(CAP_SETGID, setresgid, gid, gid, gid) < 0) { - _perr("setresgid"); - exit(1); - } - if (do_cap(CAP_SETUID, setresuid, uid, uid, uid) < 0) { - _perr("setresuid"); - exit(1); - } - } + if (exec_p) + pid = 0; + else + pid = fork(); + + if (pid < 0) + { + _perr("fork"); + return -1; + } + + if (pid == 0) /* child process, or exec_p */ + { + /* Make sure we run as the full user. If we're + * switching to a non-root user, this won't allow + * that process to switch back to root (since the + * original process is setuid). */ + if (setresgid (gid, gid, gid) < 0) { + _perr("setresgid"); + exit(1); + } + if (setresuid (uid, uid, uid) < 0) { + _perr("setresuid"); + exit(1); + } - /* Actually run the command. */ - if (execv(path, argv) < 0) - perror(path); - _exit(1); - } + /* Actually run the command. */ + if (execv(path, argv) < 0) + perror(path); + _exit(1); + } if (waitpid(pid, &rstatus, 0) < 0) - return -1; + return -1; if (WIFEXITED(rstatus)) - return WEXITSTATUS(rstatus); + return WEXITSTATUS(rstatus); return -1; } @@ -104,14 +111,13 @@ static int enable_uprobes(void) argv[i++] = "unregister_uprobe"; argv[i++] = "/proc/kallsyms"; argv[i] = NULL; - if (run_as(uid, gid, argv[0], argv) == 0) + if (run_as(0, uid, gid, argv[0], argv) == 0) return 0; /* * TODO: If user can't setresuid to root here, staprun will exit. * Is there a situation where that would fail but the subsequent - * attempt to use CAP_SYS_MODULE privileges (in insert_module()) - * would succeed? + * attempt to insert_module() would succeed? */ dbug(2, "Inserting uprobes module from /lib/modules, if any.\n"); i = 0; @@ -119,7 +125,7 @@ static int enable_uprobes(void) argv[i++] = "-q"; argv[i++] = "uprobes"; argv[i] = NULL; - if (run_as(0, 0, argv[0], argv) == 0) + if (run_as(0, 0, 0, argv[0], argv) == 0) return 0; dbug(2, "Inserting uprobes module from SystemTap runtime.\n"); @@ -169,9 +175,9 @@ static int remove_module(const char *name, int verb) } /* Call init_ctl_channel() which actually attempts an open() - * of the control channel. This is better than using access() because + * of the control channel. This is better than using access() because * an open on an already open channel will fail, preventing us from attempting - * to remove an in-use module. + * to remove an in-use module. */ if (init_ctl_channel(name, 0) < 0) { if (verb) @@ -186,7 +192,7 @@ static int remove_module(const char *name, int verb) if (setpriority(PRIO_PROCESS, 0, 0) < 0) _perr("setpriority"); - ret = do_cap(CAP_SYS_MODULE, delete_module, name, 0); + ret = delete_module (name, 0); if (ret != 0) { err("Error removing module '%s': %s.\n", name, strerror(errno)); return 1; @@ -203,9 +209,6 @@ int init_staprun(void) if (mountfs() < 0) return -1; - /* We're done with CAP_SYS_ADMIN. */ - drop_cap(CAP_SYS_ADMIN); - if (delete_mod) exit(remove_module(modname, 1)); else if (!attach_mod) { @@ -269,25 +272,14 @@ int main(int argc, char **argv) exit(1); } - init_cap(); - if (check_permissions() != 1) usage(argv[0]); - /* now bump the priority */ - rc = do_cap(CAP_SYS_NICE, setpriority, PRIO_PROCESS, 0, -10); - /* failure is not fatal in this case */ - if (rc < 0) - _perr("setpriority"); - - /* We're done with CAP_SYS_NICE. */ - drop_cap(CAP_SYS_NICE); - if (init_staprun()) exit(1); argv[0] = PKGLIBDIR "/stapio"; - if (execv(argv[0], argv) < 0) { + if (run_as (1, getuid(), getgid(), argv[0], argv) < 0) { perror(argv[0]); goto err; } @@ -337,7 +329,7 @@ int send_relocation_kernel () FILE* kallsyms = fopen ("/proc/kallsyms", "r"); if (kallsyms == NULL) { - perror("cannot open /proc/kallsyms"); + perror("cannot open /proc/kallsyms"); // ... and the kernel module will almost certainly fail to initialize. } else @@ -404,18 +396,18 @@ void send_relocation_modules () module_section_file = globbuf.gl_pathv[i]; - /* Tokenize the file name. + /* Tokenize the file name. Sample gl_pathv[]: /sys/modules/zlib_deflate/sections/.text Pieces: ^^^^^^^^^^^^ ^^^^^ */ - section_name = rindex (module_section_file, '/'); + section_name = rindex (module_section_file, '/'); if (! section_name) continue; section_name ++; if (!strcmp (section_name, ".")) continue; if (!strcmp (section_name, "..")) continue; - - module_name = index (module_section_file, '/'); + + module_name = index (module_section_file, '/'); if (! module_name) continue; module_name ++; module_name = index (module_name, '/'); @@ -436,7 +428,7 @@ void send_relocation_modules () /* Now we destructively modify the string, but by now the file is open so we won't need the full name again. */ *module_name_end = '\0'; - + send_a_relocation (module_name, section_name, section_address); } @@ -454,7 +446,7 @@ void send_relocation_modules () same time that a probeworthy module is being unloaded. */ } } - + globfree (& globbuf); } diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index 0a35fee6..2014ce5b 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -33,7 +33,6 @@ #include <sys/wait.h> #include <sys/statfs.h> #include <linux/version.h> -#include <sys/capability.h> #define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}} @@ -58,17 +57,6 @@ extern char *__name__; fprintf(stderr, ": %s\n", strerror(_errno)); \ } while (0) #define overflow_error() _err("Internal buffer overflow. Please file a bug report.\n") - -#define do_cap(cap,func,args...) ({ \ - int _rc, _saved_errno; \ - add_cap(cap); \ - _rc = func(args); \ - _saved_errno = errno; \ - del_cap(cap); \ - errno = _saved_errno; \ - _rc; \ - }) \ - /* Error checking version of sprintf() - returns 1 if overflow error */ #define sprintf_chk(str, args...) ({ \ @@ -123,12 +111,6 @@ void close_relayfs(void); int init_oldrelayfs(void); void close_oldrelayfs(int); void setup_signals(void); -/* cap.c */ -void print_cap(char *text); -void init_cap(void); -void add_cap(cap_value_t cap); -void del_cap(cap_value_t cap); -void drop_cap(cap_value_t cap); /* staprun_funcs.c */ void setup_staprun_signals(void); const char *moderror(int err); @@ -147,7 +129,7 @@ void setup_signals(void); int set_clexec(int fd); /* - * variables + * variables */ extern int control_channel; extern int ncpus; diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index c1cb92b7..8fa95e45 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -43,7 +43,7 @@ int insert_module(const char *path, const char *special_options, char **options) char *opts; int fd, saved_errno; struct stat sbuf; - + dbug(2, "inserting module\n"); if (special_options) @@ -71,7 +71,7 @@ int insert_module(const char *path, const char *special_options, char **options) perr("Error opening '%s'", path); return -1; } - + /* Now that the file is open, figure out how big it is. */ if (fstat(fd, &sbuf) < 0) { _perr("Error stat'ing '%s'", path); @@ -87,9 +87,9 @@ int insert_module(const char *path, const char *special_options, char **options) free(opts); return -1; } - + /* Actually insert the module */ - ret = do_cap(CAP_SYS_MODULE, init_module, file, sbuf.st_size, opts); + ret = init_module(file, sbuf.st_size, opts); saved_errno = errno; /* Cleanup. */ @@ -99,7 +99,7 @@ int insert_module(const char *path, const char *special_options, char **options) if (ret != 0) { err("Error inserting module '%s': %s\n", path, moderror(saved_errno)); - return -1; + return -1; } return 0; } @@ -120,8 +120,7 @@ int mountfs(void) rc = stat(DEBUGFSDIR, &sb); if (rc == 0 && S_ISDIR(sb.st_mode)) { /* If we can mount the debugfs dir correctly, we're done. */ - rc = do_cap(CAP_SYS_ADMIN, mount, "debugfs", DEBUGFSDIR, - "debugfs", 0, NULL); + rc = mount ("debugfs", DEBUGFSDIR, "debugfs", 0, NULL); if (rc == 0) return 0; /* If we got ENODEV, that means that debugfs isn't @@ -132,7 +131,7 @@ int mountfs(void) return -1; } } - + /* DEBUGFSDIR couldn't be mounted. So, try RELAYFSDIR. */ /* If the relayfs dir is already mounted correctly, we're done. */ @@ -159,11 +158,12 @@ int mountfs(void) /* To ensure the directory gets created with the * proper group, we'll have to temporarily switch to * root. */ - if (do_cap(CAP_SETUID, setuid, 0) < 0) { + /* XXX: Why not just chown() the thing? */ + if (setuid (0) < 0) { _perr("Couldn't change user while creating %s", RELAYFSDIR); return -1; } - if (do_cap(CAP_SETGID, setgid, 0) < 0) { + if (setgid (0) < 0) { _perr("Couldn't change group while creating %s", RELAYFSDIR); return -1; } @@ -174,11 +174,11 @@ int mountfs(void) saved_errno = errno; /* Restore everything we changed. */ - if (do_cap(CAP_SETGID, setgid, gid) < 0) { + if (setgid (gid) < 0) { _perr("Couldn't restore group while creating %s", RELAYFSDIR); return -1; } - if (do_cap(CAP_SETUID, setuid, uid) < 0) { + if (setuid (uid) < 0) { _perr("Couldn't restore user while creating %s", RELAYFSDIR); return -1; } @@ -192,7 +192,7 @@ int mountfs(void) } /* Now that we're sure the directory exists, try mounting RELAYFSDIR. */ - if (do_cap(CAP_SYS_ADMIN, mount, "relayfs", RELAYFSDIR, "relayfs", 0, NULL) < 0) { + if (mount ("relayfs", RELAYFSDIR, "relayfs", 0, NULL) < 0) { perr("Couldn't mount %s", RELAYFSDIR); return -1; } @@ -262,13 +262,13 @@ check_path(void) " Unable to canonicalize that directory", staplib_dir_path); return -1; } - + /* Use realpath() to canonicalize the module path. */ if (realpath(modpath, module_realpath) == NULL) { perr("Unable to canonicalize path \"%s\"", modpath); return -1; } - + /* To make sure the user can't specify something like * /lib/modules/`uname -r`/systemtapmod.ko, put a '/' on the * end of staplib_dir_realpath. */ diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 9c0dd55b..2d4eed15 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -360,7 +360,7 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen) | UTRACE_EVENT(EXEC) \ | UTRACE_EVENT(DEATH)) -/* +/* * __STP_TASK_BASE_EVENTS: base events for stap_task_finder_target's * without a vm_callback * @@ -460,7 +460,7 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk, else if (tgt->pid != 0) continue; /* Notice that "pid == 0" (which means to probe all - * threads) falls through. */ + * threads) falls through. */ list_for_each(cb_node, &tgt->callback_list_head) { struct stap_task_finder_target *cb_tgt; @@ -1138,6 +1138,11 @@ stap_start_task_finder(void) size_t mmpathlen; struct list_head *tgt_node; + /* Skip over processes other than that specified with + stap -c or -x. */ + if (_stp_target && tsk->tgid != _stp_target) + continue; + rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0, __STP_TASK_FINDER_EVENTS); if (rc == EPERM) { diff --git a/systemtap.spec b/systemtap.spec index 94eddf0b..5ace5632 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -18,7 +18,6 @@ Source: ftp://sourceware.org/pub/%{name}/releases/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: kernel >= 2.6.9-11 -BuildRequires: libcap-devel %if %{with_sqlite} BuildRequires: sqlite-devel Requires: sqlite diff --git a/tapsets.cxx b/tapsets.cxx index 4fa53a88..64fa9d34 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2919,6 +2919,8 @@ dwarf_query::build_blacklist() blfile += "kernel/kprobes.c"; // first alternative, no "|" blfile += "|arch/.*/kernel/kprobes.c"; + blfile += "|include/asm/io.h"; + blfile += "|drivers/ide/ide-iops.c"; // XXX: it would be nice if these blacklisted functions were pulled // in dynamically, instead of being statically defined here. @@ -5868,8 +5870,11 @@ utrace_derived_probe::utrace_derived_probe (systemtap_session &s, vector<probe_point::component*> comps; if (hp) comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path))); - else + else if (pid != 0) comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid))); + else + comps.push_back (new probe_point::component(TOK_PROCESS)); + switch (flags) { case UDPF_THREAD_BEGIN: diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 9ca00077..045772a3 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2008-09-06 Frank Ch. Eigler <fche@elastic.org> + + * systemtap.base/cmd_parse.exp: Adapt to sh-c-less "stap -c" + execution. + +2008-09-05 Stan Cox <scox@redhat.com> + + * systemtap.base/global_end.stp: Also check scalar statistics. + * systemtap.base/global_end.exp: Likeewise. + +2008-09-05 Frank Ch. Eigler <fche@elastic.org> + + PR 4255. + * systemtap.base/uprobes.{exp,stp}: New file. + 2008-09-05 Wenji Huang <wenji.huang@oracle.com> * systemtap.base/cmd_parse.stp: Add test for "-L" option. diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp index c37d358f..733881a1 100644 --- a/testsuite/systemtap.base/cmd_parse.exp +++ b/testsuite/systemtap.base/cmd_parse.exp @@ -5,76 +5,68 @@ if {![installtest_p]} { return } -# stap -c 'echo "hello world"' -e 'probe begin {}' -spawn stap -c {echo "hello world"} -e {probe begin {}} +spawn stap -c {echo "hello world"} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse1"} timeout {fail "cmd_parse1: unexpected timeout"} eof {fail "cmd_parse1: unexpected EOF"} } -wait +wait;close -# stap -c 'echo "hello "\"world\"' -e 'probe begin {}' -spawn stap -c {echo "hello "\"world\"} -e {probe begin {}} +spawn stap -c {echo "hello "\"world\"} -we {probe begin {}} expect { -timeout 60 "hello \"world\"" {pass "cmd_parse2"} timeout {fail "cmd_parse2: unexpected timeout"} eof {fail "cmd_parse2: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello world"; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello world"; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello world"; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse3"} timeout {fail "cmd_parse3: unexpected timeout"} eof {fail "cmd_parse3: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello "\"world\"; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello "\"world\"; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello "\"world\"; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello \"world\"" {pass "cmd_parse4"} timeout {fail "cmd_parse4: unexpected timeout"} eof {fail "cmd_parse4: unexpected EOF"} } -wait +wait;close -#stap -c '(a="hello "world; echo $a)' -e 'probe begin {}' -spawn stap -c {(a="hello "world; echo $a)} -e {probe begin {}} +spawn stap -c {sh -c '(a="hello "world; echo $a)'} -we {probe begin {}} expect { -timeout 60 "hello world" {pass "cmd_parse5"} timeout {fail "cmd_parse5: unexpected timeout"} eof {fail "cmd_parse5: unexpected EOF"} } -wait +wait;close -#stap -c '(((a=42+7)); echo "The answer is $a")' -e 'probe begin {}' -# NB: not ((a=42+7)) - must not assume bash -spawn stap -c {(a=49; echo "The answer is $a")} -e {probe begin {}} +spawn stap -c {bash -c '((a=42+7)); echo "The answer is $a"'} -we {probe begin {}} expect { -timeout 60 "The answer is 49" {pass "cmd_parse6"} timeout {fail "cmd_parse6: unexpected timeout"} eof {fail "cmd_parse6: unexpected EOF"} } -wait +wait;close -#stap -c '(echo "Hello World" 1>&2) > /dev/null' -e 'probe begin {}' -spawn stap -c {(echo "Hello World" 1>&2) > /dev/null} -e {probe begin {}} +spawn stap -c {sh -c '(echo "Hello World" 1>&2) > /dev/null'} -we {probe begin {}} expect { -timeout 60 "Hello World" {pass "cmd_parse7"} timeout {fail "cmd_parse7: unexpected timeout"} eof {fail "cmd_parse7: unexpected EOF"} } -wait +wait;close spawn stap -l {vm.*} expect { @@ -83,7 +75,7 @@ expect { timeout {fail "cmd_parse8: unexpected timeout"} eof {fail "cmd_parse8: unexpected EOF"} } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 1 expect { @@ -92,7 +84,7 @@ expect { timeout { fail "cmd_parse9 timeout" } eof { fail "cmd_parse9 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 5 a b c d expect { @@ -101,7 +93,7 @@ expect { timeout { fail "cmd_parse10 timeout" } eof { fail "cmd_parse10 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 10 a b c d expect { @@ -110,7 +102,7 @@ expect { timeout { fail "cmd_parse11 timeout" } eof { fail "cmd_parse11 eof" } } -wait +wait;close spawn stap -e {probe begin { printf("%d %s\n", argc, argv[0]) exit() }} expect { @@ -119,7 +111,7 @@ expect { timeout { fail "cmd_parse12 timeout" } eof { fail "cmd_parse12 eof" } } -wait +wait;close spawn stap -L syscall.a* expect { @@ -128,4 +120,4 @@ expect { timeout {fail "cmd_parse13: unexpected timeout"} eof {fail "cmd_parse13: unexpected EOF"} } -wait +wait;close diff --git a/testsuite/systemtap.base/global_end.exp b/testsuite/systemtap.base/global_end.exp index d066cf9d..cd5c6f83 100644 --- a/testsuite/systemtap.base/global_end.exp +++ b/testsuite/systemtap.base/global_end.exp @@ -18,8 +18,9 @@ expect { -re {iota."two".="twelve"} { incr ok; exp_continue } -re {epsilon."one",1. @count=0x4 @min=0x1 @max=0x4 @sum=0xa @avg=0x2} { incr ok; exp_continue } -re {epsilon."two",2. @count=0x4 @min=0xa @max=0x28 @sum=0x64 @avg=0x19} { incr ok; exp_continue } + -re {phi @count=0x4 @min=0x1 @max=0x4 @sum=0xa @avg=0x2} { incr ok; exp_continue } timeout { fail "$test (timeout)" } eof { } } wait -if {$ok == 10} { pass "$test ($ok)" } { fail "$test ($ok)" } +if {$ok == 11} { pass "$test ($ok)" } { fail "$test ($ok)" } diff --git a/testsuite/systemtap.base/global_end.stp b/testsuite/systemtap.base/global_end.stp index b26b7c03..876eac8c 100644 --- a/testsuite/systemtap.base/global_end.stp +++ b/testsuite/systemtap.base/global_end.stp @@ -1,4 +1,4 @@ -global alpha, beta, gamma, iota, epsilon +global alpha, beta, gamma, iota, epsilon, phi probe begin { gamma = "abcdefghijklmnopqrstuvwxyz" @@ -16,6 +16,11 @@ probe begin { beta["two",1] = 3 beta["two",2] = 4 + phi <<< 1 + phi <<< 2 + phi <<< 3 + phi <<< 4 + epsilon["one",1] <<< 1 epsilon["one",1] <<< 2 epsilon["one",1] <<< 3 diff --git a/testsuite/systemtap.base/uprobes.exp b/testsuite/systemtap.base/uprobes.exp new file mode 100644 index 00000000..a0ae3e76 --- /dev/null +++ b/testsuite/systemtap.base/uprobes.exp @@ -0,0 +1,36 @@ + + +set test uprobes + +# Compile a little C program to use as the user-space probing victim +set path "jennie.c" +set fp [open $path "w"] +puts $fp "int main (int argc, char *argv[])" +puts $fp "{" +puts $fp "if (argc > 1) main (argc - 1, argv);" +puts $fp "}" +close $fp + +# too easy +if [file exists $path] then { pass "$test prep" } else { fail "$test prep" } + +catch {exec gcc -g -o jennie jennie.c} err +if {$err == "" && [file exists jennie]} then { pass "$test compile" } else { pass "$test compile" } + +set rc [stap_run_batch $srcdir/$subdir/uprobes.stp] +if {$rc == 0} then { pass "$test -p4" } else { fail "$test -p4" } + +if {! [installtest_p]} { untested "$test -p5"; return } + +spawn sudo stap -v $srcdir/$subdir/uprobes.stp -c "./jennie 1 2 3 4" +set ok 0 +expect { + -re {^Pass[^\r\n]*\r\n} { exp_continue } + -re {^process[^\r\n]*jennie[^\r\n]*main[^\r\n]*call[^\r\n]*\r\n} { incr ok; exp_continue } + -re {^process[^\r\n]*jennie[^\r\n]*main[^\r\n]*return[^\r\n]*\r\n} { incr ok; exp_continue } + -timeout 30 + timeout { } + eof { } +} +if {$ok == 10} then { pass "$test -p5" } else { fail "$test -p5 ($ok)" } +catch {wait; close} diff --git a/testsuite/systemtap.base/uprobes.stp b/testsuite/systemtap.base/uprobes.stp new file mode 100755 index 00000000..d7efb586 --- /dev/null +++ b/testsuite/systemtap.base/uprobes.stp @@ -0,0 +1,3 @@ +#! stap -p4 +probe process("./jennie").function("main").call { log(pp()." "/*.$$parms*/) } +probe process("./jennie").function("main").return { log(pp()." "/*.$$return*/) } |