diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2008-01-24 23:48:06 -0500 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2008-01-24 23:48:06 -0500 |
commit | a1732c4f7856621604a1cc45a29af618aaa502e0 (patch) | |
tree | 29e3f9c4405e1fd1f81b8c87ac2e485855541a66 | |
parent | 7ee3e80ec0b7880c33d0ca3018025855d9dd5123 (diff) | |
parent | 674427d3a018d0f89c9669db8dcf952aab8b4423 (diff) | |
download | systemtap-steved-a1732c4f7856621604a1cc45a29af618aaa502e0.tar.gz systemtap-steved-a1732c4f7856621604a1cc45a29af618aaa502e0.tar.xz systemtap-steved-a1732c4f7856621604a1cc45a29af618aaa502e0.zip |
Merge branch 'master' of git://sources.redhat.com/git/systemtap
42 files changed, 868 insertions, 273 deletions
@@ -1,3 +1,96 @@ +2008-01-24 Frank Ch. Eigler <fche@elastic.org> + + * Makefile.am: Make another $(MKDIR) call visible. + * Makefile.in: Regenerated. + +2008-01-24 David Smith <dsmith@redhat.com> + + PR 5661 (reverted). + * configure.ac: Removed elfutils version number check. + * configure: Regenerated. + * acsite.m4: Removed. + * systemtap.spec.in: Minimum elfutils version number is no longer + filled in by configure. + + PR 5650 (partial). + * configure.ac: Handles sqlite optional functionality correctly. + If enabled/disabled by the user, do the right thing. If not + specified by the user, use it if present. + * configure: Regenerated. + * systemtap.spec.in: Always specify to configure whether to use + sqlite or not. + +2008-01-24 Dave Brolley <brolley@redhat.com> + + PR 5017. + * staptree.cxx (<cstring>): #include it. + (required <indexable *>): Remove 'static' from instantiation and + move instantiation to here from... + * staptree.h: ...here. + +2008-01-23 David Smith <dsmith@redhat.com> + + PR 5661. + * configure.ac: Checks elfutils version number. + * acsite.m4: New file containing macro to return elfutils version + number. + * configure: Regenerated. + * systemtap.spec.in: Minimum elfutils version number is now filled + in by configure. + +2008-01-23 Dave Brolley <brolley@redhat.com> + + PR 5613. + * translate.cxx (var::fini): New method. + (c_unparser::emit_module_init): Call var::fini when deregistering + variables without indices. + (c_unparser::emit_module_exit): Likewise. + +2008-01-23 Frank Ch. Eigler <fche@elastic.org> + + PR 2151. + * tapsets.cxx (dwflpp::setup): Parametrize debuginfo_path. + * stap.1.in: Document this. + +2008-01-22 Jim Keniston <jkenisto@us.ibm.com> + + * runtime/uprobes/uprobes.c: Fix from Srinivasa: Recast + rcu_dereferences of engine->data to resync with kernel.org + builds. + +2008-01-18 Jim Keniston <jkenisto@us.ibm.com> + + * runtime/uprobes/uprobes.c: Added static copy of + access_process_vm(), for kernels that don't export it. + +2008-01-18 Frank Ch. Eigler <fche@elastic.org> + + * configure.ac, systemtap.spec.in: Update version to 0.6.1 + * configure: Regenerated. + +2008-01-17 Frank Ch. Eigler <fche@elastic.org> + + PR 4935. + Reorganize probe condition implementation. + * elaborate.cxx (add_condition): New function. + (derived_probe): Remove condition member. + (derived_probe ctors): Assert non-null incoming probe/location ptrs. + (insert_condition_statement): Remove; turn into ... + (semantic_pass_conditions): New pass-2 subpass. + (semantic_pass_symbols, visit_symbol, visit_functioncall, find_var): + Detect some condition-related error cases. + (match_key): Change type to exp_type from tok_type. Update callers. + (alias_expansion_builder): Propagate probe conditions. + * staptree.cxx (probe): Remove condition field and related functions. + * tapsets.cxx (dwarf_derived_probe ctor): Compute replacement + wildcard-expanded probe_point preserving more of the original + location. + (mark_derived_probe ctor): Make similar to others - take location + rather than condition parameters. + * translate.cxx (emit_common_header): Tweak ordering of tmpcounter + traversal and hashkey expression generation. + * elaborate.h: Corresponding changes. + 2008-01-17 David Smith <dsmith@redhat.com> * tapsets.cxx diff --git a/Makefile.am b/Makefile.am index df86dc80..291adfd9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,7 +91,7 @@ $(STAPLOG): staplog.c $(CC) -Wall -shared -rdynamic $(LDFLAGS) $(CFLAGS) -fPIC -o $@ $< all-local: $(STAPLOG) install-exec-local: $(STAPLOG) - -$(MKDIR_P) $(DESTDIR)$(pkglibdir) + $(MKDIR_P) $(DESTDIR)$(pkglibdir) $(INSTALL) $(STAPLOG) $(DESTDIR)$(pkglibdir) else endif diff --git a/Makefile.in b/Makefile.in index 27577e66..d92d7a94 100644 --- a/Makefile.in +++ b/Makefile.in @@ -181,6 +181,7 @@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ +ELFUTILS_REQUIRED_VERSION = @ELFUTILS_REQUIRED_VERSION@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ @@ -1476,7 +1477,7 @@ install-exec-hook: @BUILD_CRASHMOD_TRUE@ $(CC) -Wall -shared -rdynamic $(LDFLAGS) $(CFLAGS) -fPIC -o $@ $< @BUILD_CRASHMOD_TRUE@all-local: $(STAPLOG) @BUILD_CRASHMOD_TRUE@install-exec-local: $(STAPLOG) -@BUILD_CRASHMOD_TRUE@ -$(MKDIR_P) $(DESTDIR)$(pkglibdir) +@BUILD_CRASHMOD_TRUE@ $(MKDIR_P) $(DESTDIR)$(pkglibdir) @BUILD_CRASHMOD_TRUE@ $(INSTALL) $(STAPLOG) $(DESTDIR)$(pkglibdir) # Copy some of the testsuite sample scripts to the distdir @@ -1,4 +1,4 @@ -* What's new in version 0.6 / since version 0.5.15? +* What's new in version 0.6 / 0.6.1 - Crash utility can retrieve systemtap's relay buffer from a kernel dump image by using staplog which is a crash extension module. To use this diff --git a/buildrun.cxx b/buildrun.cxx index 2f7c358d..b41b9545 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -88,6 +88,9 @@ compile_pass (systemtap_session& s) o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-constant-tsc.c, -DSTAPCONF_CONSTANT_TSC,)" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-tsc-khz.c, -DSTAPCONF_TSC_KHZ,)" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-ktime-get-real.c, -DSTAPCONF_KTIME_GET_REAL,)" << endl; + o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-x86-uniregs.c, -DSTAPCONF_X86_UNIREGS,)" << endl; + + o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-nameidata.c, -DSTAPCONF_NAMEIDATA_CLEANUP,)" << endl; for (unsigned i=0; i<s.macros.size(); i++) o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl; @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for systemtap 0.6. +# Generated by GNU Autoconf 2.61 for systemtap 0.6.1. # # Report bugs to <systemtap@sources.redhat.com>. # @@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='systemtap' PACKAGE_TARNAME='systemtap' -PACKAGE_VERSION='0.6' -PACKAGE_STRING='systemtap 0.6' +PACKAGE_VERSION='0.6.1' +PACKAGE_STRING='systemtap 0.6.1' PACKAGE_BUGREPORT='systemtap@sources.redhat.com' # Factoring default headers for most tests. @@ -1233,7 +1233,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures systemtap 0.6 to adapt to many kinds of systems. +\`configure' configures systemtap 0.6.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1299,7 +1299,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of systemtap 0.6:";; + short | recursive ) echo "Configuration of systemtap 0.6.1:";; esac cat <<\_ACEOF @@ -1313,6 +1313,7 @@ Optional Features: --enable-perfmon enable perfmon support (default is disabled) --enable-prologues make -P prologue-searching default --enable-ssp enable gcc stack-protector + --enable-sqlite build with sqlite support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1398,7 +1399,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -systemtap configure 0.6 +systemtap configure 0.6.1 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1412,7 +1413,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by systemtap $as_me 0.6, which was +It was created by systemtap $as_me 0.6.1, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -1767,7 +1768,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu - am__api_version='1.10' ac_aux_dir= @@ -2105,7 +2105,7 @@ fi # Define the identity of the package. PACKAGE='systemtap' - VERSION='0.6' + VERSION='0.6.1' cat >>confdefs.h <<_ACEOF @@ -5823,8 +5823,6 @@ fi - - # Check whether --enable-perfmon was given. if test "${enable_perfmon+set}" = set; then enableval=$enable_perfmon; perfmon_support=$enableval @@ -5959,10 +5957,28 @@ fi fi +# Check whether --enable-ssp was given. +if test "${enable_ssp+set}" = set; then + enableval=$enable_ssp; +fi + +if test "x$enable_ssp" == xyes; then + CFLAGS="$CFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2" + CXXFLAGS="$CXXFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2" + { echo "$as_me:$LINENO: Compiling with gcc -fstack-protector-all et al." >&5 +echo "$as_me: Compiling with gcc -fstack-protector-all et al." >&6;} +fi -SAVE_LIBS="$LIBS" -{ echo "$as_me:$LINENO: checking for sqlite3_open in -lsqlite3" >&5 +# Check whether --enable-sqlite was given. +if test "${enable_sqlite+set}" = set; then + enableval=$enable_sqlite; +else + enable_sqlite=check +fi + sqlite3_LIBS= +if test "x$enable_sqlite" != xno; then + { echo "$as_me:$LINENO: checking for sqlite3_open in -lsqlite3" >&5 echo $ECHO_N "checking for sqlite3_open in -lsqlite3... $ECHO_C" >&6; } if test "${ac_cv_lib_sqlite3_sqlite3_open+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -6024,17 +6040,19 @@ fi { echo "$as_me:$LINENO: result: $ac_cv_lib_sqlite3_sqlite3_open" >&5 echo "${ECHO_T}$ac_cv_lib_sqlite3_sqlite3_open" >&6; } if test $ac_cv_lib_sqlite3_sqlite3_open = yes; then - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBSQLITE3 1 -_ACEOF - - LIBS="-lsqlite3 $LIBS" + sqlite3_LIBS=-lsqlite3 +else + if test "x$enable_sqlite" != xcheck; then + { { echo "$as_me:$LINENO: error: --enable-sqlite was given, but test for sqlite failed +See \`config.log' for more details." >&5 +echo "$as_me: error: --enable-sqlite was given, but test for sqlite failed +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi fi -sqlite3_LIBS="$LIBS" - -LIBS="$SAVE_LIBS" +fi # Check whether --enable-ssp was given. @@ -6454,6 +6472,7 @@ echo "$as_me: error: missing elfutils development headers/libraries (ebl 0.123+) { (exit 1); exit 1; }; } fi + stap_LIBS="$LIBS" LIBS="$SAVE_LIBS" else @@ -7031,7 +7050,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by systemtap $as_me 0.6, which was +This file was extended by systemtap $as_me 0.6.1, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7084,7 +7103,7 @@ Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -systemtap config.status 0.6 +systemtap config.status 0.6.1 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 256155a8..f53fca84 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,9 @@ dnl configure.ac --- autoconf input file for systemtap dnl Process this file with autoconf to produce a configure script. -AC_INIT([systemtap], 0.6, systemtap@sources.redhat.com, systemtap) +AC_INIT([systemtap], 0.6.1, systemtap@sources.redhat.com, systemtap) dnl ^^^ see also NEWS, testsuite/configure.ac - AC_PREREQ(2.59) AM_INIT_AUTOMAKE AM_MAINTAINER_MODE @@ -25,8 +24,6 @@ AC_PROG_MAKE_SET AC_SUBST(CFLAGS) AC_SUBST(CXXFLAGS) - - dnl enable option to generate code for using perfmon AC_ARG_ENABLE(perfmon, [ --enable-perfmon enable perfmon support (default is disabled)], @@ -76,13 +73,27 @@ if test "$enable_prologues" = yes; then AC_DEFINE([ENABLE_PROLOGUES],[],[make -P prologue-searching default]) fi]) +AC_ARG_ENABLE([ssp], + [AC_HELP_STRING([--enable-ssp], [enable gcc stack-protector])]) +AS_IF([test "x$enable_ssp" == xyes], + [CFLAGS="$CFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2" + CXXFLAGS="$CXXFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2" + AC_MSG_NOTICE([Compiling with gcc -fstack-protector-all et al.])]) -SAVE_LIBS="$LIBS" -AC_CHECK_LIB(sqlite3, sqlite3_open) -sqlite3_LIBS="$LIBS" -AC_SUBST(sqlite3_LIBS) -LIBS="$SAVE_LIBS" - +dnl Handle optional sqlite support. If enabled/disabled by the user, +dnl do the right thing. If not specified by the user, use it if +dnl present. +AC_ARG_ENABLE([sqlite], + AS_HELP_STRING([--enable-sqlite], [build with sqlite support]), + [], dnl ACTION-IF-GIVEN + [enable_sqlite=check]) dnl ACTION-IF-NOT-GIVEN +sqlite3_LIBS= +AS_IF([test "x$enable_sqlite" != xno], + [AC_CHECK_LIB([sqlite3], [sqlite3_open], + [AC_SUBST([sqlite3_LIBS], [-lsqlite3])], + [if test "x$enable_sqlite" != xcheck; then + AC_MSG_FAILURE([--enable-sqlite was given, but test for sqlite failed]) + fi])]) AC_ARG_ENABLE([ssp], [AC_HELP_STRING([--enable-ssp], [enable gcc stack-protector])]) @@ -122,6 +133,7 @@ if test $build_elfutils = no; then AC_MSG_ERROR([missing elfutils development headers/libraries (dw 0.123+)])]) AC_CHECK_LIB(ebl, ebl_openbackend,,[ AC_MSG_ERROR([missing elfutils development headers/libraries (ebl 0.123+)])]) + stap_LIBS="$LIBS" LIBS="$SAVE_LIBS" else diff --git a/elaborate.cxx b/elaborate.cxx index 0ac0f4da..39dae294 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -33,60 +33,49 @@ using namespace std; // ------------------------------------------------------------------------ +// Used in probe_point condition construction. Either argument may be +// NULL; if both, return NULL too. Resulting expression is a deep +// copy for symbol resolution purposes. +expression* add_condition (expression* a, expression* b) +{ + if (!a && !b) return 0; + if (! a) return deep_copy_visitor::deep_copy(b); + if (! b) return deep_copy_visitor::deep_copy(a); + logical_and_expr la; + la.op = "&&"; + la.left = a; + la.right = b; + la.tok = a->tok; // or could be b->tok + return deep_copy_visitor::deep_copy(& la); +} + +// ------------------------------------------------------------------------ + + derived_probe::derived_probe (probe *p): base (p) { - if (p) - { - this->locations = p->locations; - this->condition = deep_copy_visitor::deep_copy(p->condition); - this->tok = p->tok; - this->privileged = p->privileged; - this->body = deep_copy_visitor::deep_copy(p->body); - } + assert (p); + this->locations = p->locations; + this->tok = p->tok; + this->privileged = p->privileged; + this->body = deep_copy_visitor::deep_copy(p->body); } derived_probe::derived_probe (probe *p, probe_point *l): base (p) { - if (p) - { - if (p->condition) - this->condition = deep_copy_visitor::deep_copy(p->condition); - this->tok = p->tok; - this->privileged = p->privileged; - this->body = deep_copy_visitor::deep_copy(p->body); - } + assert (p); + this->tok = p->tok; + this->privileged = p->privileged; + this->body = deep_copy_visitor::deep_copy(p->body); - if (l) - { - probe_point *pp = new probe_point (l->components, l->tok); - this->locations.push_back (pp); - this->add_condition (l->condition); - this->insert_condition_statement (); - } + assert (l); + this->locations.push_back (l); } -void -derived_probe::insert_condition_statement (void) -{ - if (this->condition) - { - if_statement *ifs = new if_statement (); - ifs->tok = this->tok; - ifs->thenblock = new next_statement (); - ifs->thenblock->tok = this->tok; - ifs->elseblock = NULL; - unary_expression *notex = new unary_expression (); - notex->op = "!"; - notex->tok = this->tok; - notex->operand = this->condition; - ifs->condition = notex; - body->statements.insert (body->statements.begin(), ifs); - } -} void derived_probe::printsig (ostream& o) const @@ -196,14 +185,14 @@ derived_probe_builder::has_null_param (std::map<std::string, literal*> const & p match_key::match_key(string const & n) : name(n), have_parameter(false), - parameter_type(tok_junk) + parameter_type(pe_unknown) { } match_key::match_key(probe_point::component const & c) : name(c.functor), have_parameter(c.arg != NULL), - parameter_type(c.arg ? c.arg->tok->type : tok_junk) + parameter_type(c.arg ? c.arg->type : pe_unknown) { } @@ -211,7 +200,7 @@ match_key & match_key::with_number() { have_parameter = true; - parameter_type = tok_number; + parameter_type = pe_long; return *this; } @@ -219,7 +208,7 @@ match_key & match_key::with_string() { have_parameter = true; - parameter_type = tok_string; + parameter_type = pe_string; return *this; } @@ -229,8 +218,8 @@ match_key::str() const if (have_parameter) switch (parameter_type) { - case tok_string: return name + "(string)"; - case tok_number: return name + "(number)"; + case pe_string: return name + "(string)"; + case pe_long: return name + "(number)"; default: return name + "(...)"; } return name; @@ -371,6 +360,10 @@ match_node::find_and_build (systemtap_session& s, non_wildcard_component->functor = subkey.name; non_wildcard_pp->components[pos] = non_wildcard_component; + // NB: probe conditions are not attached at the wildcard + // (component/functor) level, but at the overall + // probe_point level. + // recurse (with the non-wildcard probe point) try { @@ -439,7 +432,7 @@ match_node::build_no_more (systemtap_session& s) struct alias_derived_probe: public derived_probe { - alias_derived_probe (probe* base): derived_probe (base) {} + alias_derived_probe (probe* base, probe_point *l): derived_probe (base, l) {} void upchuck () { throw semantic_error ("inappropriate", this->tok); } @@ -471,17 +464,18 @@ alias_expansion_builder // alias_expansion_probe so that the expansion loop recognizes it as // such and re-expands its expansion. - probe * n = new alias_derived_probe (use); + alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */); n->body = new block(); - // The new probe gets the location list of the alias, + // The new probe gets the location list of the alias (with incoming condition joined) n->locations = alias->locations; - + for (unsigned i=0; i<n->locations.size(); i++) + n->locations[i]->condition = add_condition (n->locations[i]->condition, + location->condition); + // the token location of the alias, n->tok = location->tok; n->body->tok = location->tok; - // The new probe takes over condition. - n->add_condition (location->condition); // and statements representing the concatenation of the alias' // body with the use's. @@ -813,40 +807,6 @@ struct no_var_mutation_during_iteration_check }; -static int -semantic_pass_vars (systemtap_session & sess) -{ - - map<functiondecl *, set<vardecl *> *> fmv; - no_var_mutation_during_iteration_check chk(sess, fmv); - - for (unsigned i = 0; i < sess.functions.size(); ++i) - { - functiondecl * fn = sess.functions[i]; - if (fn->body) - { - set<vardecl *> * m = new set<vardecl *>(); - mutated_var_collector mc (m); - fn->body->visit (&mc); - fmv[fn] = m; - } - } - - for (unsigned i = 0; i < sess.functions.size(); ++i) - { - if (sess.functions[i]->body) - sess.functions[i]->body->visit (&chk); - } - - for (unsigned i = 0; i < sess.probes.size(); ++i) - { - if (sess.probes[i]->body) - sess.probes[i]->body->visit (&chk); - } - - return sess.num_errors(); -} - // ------------------------------------------------------------------------ struct stat_decl_collector @@ -950,6 +910,106 @@ semantic_pass_stats (systemtap_session & sess) // ------------------------------------------------------------------------ +// Enforce variable-related invariants: no modification of +// a foreach()-iterated array. +static int +semantic_pass_vars (systemtap_session & sess) +{ + + map<functiondecl *, set<vardecl *> *> fmv; + no_var_mutation_during_iteration_check chk(sess, fmv); + + for (unsigned i = 0; i < sess.functions.size(); ++i) + { + functiondecl * fn = sess.functions[i]; + if (fn->body) + { + set<vardecl *> * m = new set<vardecl *>(); + mutated_var_collector mc (m); + fn->body->visit (&mc); + fmv[fn] = m; + } + } + + for (unsigned i = 0; i < sess.functions.size(); ++i) + { + if (sess.functions[i]->body) + sess.functions[i]->body->visit (&chk); + } + + for (unsigned i = 0; i < sess.probes.size(); ++i) + { + if (sess.probes[i]->body) + sess.probes[i]->body->visit (&chk); + } + + return sess.num_errors(); +} + + +// ------------------------------------------------------------------------ + +// Rewrite probe condition expressions into probe bodies. Tricky and +// exciting business, this. This: +// +// probe foo if (g1 || g2) { ... } +// probe bar { ... g1 ++ ... } +// +// becomes: +// +// probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} } +// probe foo { if (! (g1 || g2)) next; ... } +// probe bar { ... g1 ++ ...; +// if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %} +// } +// +// XXX: As a first cut, do only the "inline probe condition" part of the +// transform. + +static int +semantic_pass_conditions (systemtap_session & sess) +{ + for (unsigned i = 0; i < sess.probes.size(); ++i) + { + derived_probe* p = sess.probes[i]; + expression* e = p->sole_location()->condition; + if (e) + { + varuse_collecting_visitor vut; + e->visit (& vut); + + if (! vut.written.empty()) + { + string err = ("probe condition must not modify any variables"); + sess.print_error (semantic_error (err, e->tok)); + } + else if (vut.embedded_seen) + { + sess.print_error (semantic_error ("probe condition must not include impure embedded-C", e->tok)); + } + + // Add the condition expression to the front of the + // derived_probe body. + if_statement *ifs = new if_statement (); + ifs->tok = e->tok; + ifs->thenblock = new next_statement (); + ifs->thenblock->tok = e->tok; + ifs->elseblock = NULL; + unary_expression *notex = new unary_expression (); + notex->op = "!"; + notex->tok = e->tok; + notex->operand = e; + ifs->condition = notex; + p->body->statements.insert (p->body->statements.begin(), ifs); + } + } + + return sess.num_errors(); +} + + +// ------------------------------------------------------------------------ + static int semantic_pass_symbols (systemtap_session&); static int semantic_pass_optimize1 (systemtap_session&); @@ -957,7 +1017,7 @@ static int semantic_pass_optimize2 (systemtap_session&); static int semantic_pass_types (systemtap_session&); static int semantic_pass_vars (systemtap_session&); static int semantic_pass_stats (systemtap_session&); - +static int semantic_pass_conditions (systemtap_session&); // Link up symbols to their declarations. Set the session's @@ -1030,6 +1090,12 @@ semantic_pass_symbols (systemtap_session& s) sym.current_function = 0; sym.current_probe = dp; dp->body->visit (& sym); + + // Process the probe-point condition expression. + sym.current_function = 0; + sym.current_probe = 0; + if (dp->sole_location()->condition) + dp->sole_location()->condition->visit (& sym); } catch (const semantic_error& e) { @@ -1058,7 +1124,8 @@ semantic_pass (systemtap_session& s) s.register_library_aliases(); register_standard_tapsets(s); - rc = semantic_pass_symbols (s); + if (rc == 0) rc = semantic_pass_symbols (s); + if (rc == 0) rc = semantic_pass_conditions (s); if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize1 (s); if (rc == 0) rc = semantic_pass_types (s); if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize2 (s); @@ -1248,8 +1315,8 @@ symresolution_info::visit_symbol (symbol* e) else if (current_probe) current_probe->locals.push_back (v); else - // must not happen - throw semantic_error ("no current probe/function", e->tok); + // must be probe-condition expression + throw semantic_error ("probe condition must not reference undeclared global", e->tok); e->referent = v; } } @@ -1301,6 +1368,14 @@ symresolution_info::visit_arrayindex (arrayindex* e) void symresolution_info::visit_functioncall (functioncall* e) { + // XXX: we could relax this, if we're going to examine the + // vartracking data recursively. See testsuite/semko/fortytwo.stp. + if (! (current_function || current_probe)) + { + // must be probe-condition expression + throw semantic_error ("probe condition must not reference function", e->tok); + } + for (unsigned i=0; i<e->args.size(); i++) e->args[i]->visit (this); @@ -1323,20 +1398,22 @@ symresolution_info::visit_functioncall (functioncall* e) vardecl* symresolution_info::find_var (const string& name, int arity) { - - // search locals - vector<vardecl*>& locals = (current_function ? - current_function->locals : - current_probe->locals); - - - for (unsigned i=0; i<locals.size(); i++) - if (locals[i]->name == name - && locals[i]->compatible_arity(arity)) - { - locals[i]->set_arity (arity); - return locals[i]; - } + if (current_function || current_probe) + { + // search locals + vector<vardecl*>& locals = (current_function ? + current_function->locals : + current_probe->locals); + + + for (unsigned i=0; i<locals.size(); i++) + if (locals[i]->name == name + && locals[i]->compatible_arity(arity)) + { + locals[i]->set_arity (arity); + return locals[i]; + } + } // search function formal parameters (for scalars) if (arity == 0 && current_function) @@ -1430,7 +1507,11 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) { functioncall_traversing_visitor ftv; for (unsigned i=0; i<s.probes.size(); i++) - s.probes[i]->body->visit (& ftv); + { + s.probes[i]->body->visit (& ftv); + if (s.probes[i]->sole_location()->condition) + s.probes[i]->sole_location()->condition->visit (& ftv); + } for (unsigned i=0; i<s.functions.size(); /* see below */) { if (ftv.traversed.find(s.functions[i]) == ftv.traversed.end()) @@ -1463,7 +1544,13 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) varuse_collecting_visitor vut; for (unsigned i=0; i<s.probes.size(); i++) - s.probes[i]->body->visit (& vut); + { + s.probes[i]->body->visit (& vut); + + if (s.probes[i]->sole_location()->condition) + s.probes[i]->sole_location()->condition->visit (& vut); + } + // NB: Since varuse_collecting_visitor also traverses down // actually called functions, we don't need to explicitly // iterate over them. Uncalled ones should have been pruned @@ -1985,6 +2072,15 @@ semantic_pass_types (systemtap_session& s) ti.current_probe = pn; ti.t = pe_unknown; pn->body->visit (& ti); + + probe_point* pp = pn->sole_location(); + if (pp->condition) + { + ti.current_function = 0; + ti.current_probe = 0; + ti.t = pe_long; // NB: expected type + pp->condition->visit (& ti); + } } for (unsigned j=0; j<s.globals.size(); j++) @@ -2853,7 +2949,7 @@ typeresolution_info::unresolved (const token* tok) stringstream msg; string nm = (current_function ? current_function->name : current_probe ? current_probe->name : - "?"); + "probe condition"); msg << nm + " with unresolved type"; session.print_error (semantic_error (msg.str(), tok)); } @@ -2870,7 +2966,7 @@ typeresolution_info::invalid (const token* tok, exp_type pe) stringstream msg; string nm = (current_function ? current_function->name : current_probe ? current_probe->name : - "?"); + "probe condition"); if (tok && tok->type == tok_operator) msg << nm + " uses invalid operator"; else @@ -2890,7 +2986,7 @@ typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2) stringstream msg; string nm = (current_function ? current_function->name : current_probe ? current_probe->name : - "?"); + "probe condition"); msg << nm + " with type mismatch (" << t1 << " vs. " << t2 << ")"; session.print_error (semantic_error (msg.str(), tok)); } diff --git a/elaborate.h b/elaborate.h index 13246b86..5f396526 100644 --- a/elaborate.h +++ b/elaborate.h @@ -118,7 +118,6 @@ struct derived_probe: public probe virtual probe_point* sole_location () const; virtual void printsig (std::ostream &o) const; void printsig_nested (std::ostream &o) const; - void insert_condition_statement (void); virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list); virtual void emit_probe_context_vars (translator_output*) {} @@ -197,7 +196,7 @@ match_key { std::string name; bool have_parameter; - token_type parameter_type; + exp_type parameter_type; match_key(std::string const & n); match_key(probe_point::component const & c); diff --git a/runtime/autoconf-nameidata.c b/runtime/autoconf-nameidata.c new file mode 100644 index 00000000..c1d02400 --- /dev/null +++ b/runtime/autoconf-nameidata.c @@ -0,0 +1,4 @@ +#include <linux/namei.h> + +struct nameidata nd __attribute__ ((unused)) = {.path={(void *)0}}; + diff --git a/runtime/autoconf-x86-uniregs.c b/runtime/autoconf-x86-uniregs.c new file mode 100644 index 00000000..25729c22 --- /dev/null +++ b/runtime/autoconf-x86-uniregs.c @@ -0,0 +1,6 @@ +#include <asm/ptrace.h> + +#if defined (__i386__) || defined (__x86_64__) +struct pt_regs regs = {.ax = 0x0}; +#endif + diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 8dbff764..4674e399 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -75,7 +75,37 @@ }) -#if defined __i386__ +#if defined (STAPCONF_X86_UNIREGS) && defined (__i386__) + +#define dwarf_register_0(regs) regs->ax +#define dwarf_register_1(regs) regs->cx +#define dwarf_register_2(regs) regs->dx +#define dwarf_register_3(regs) regs->bx +#define dwarf_register_4(regs) ((long) ®s->sp) +#define dwarf_register_5(regs) regs->bp +#define dwarf_register_6(regs) regs->si +#define dwarf_register_7(regs) regs->di + +#elif defined (STAPCONF_X86_UNIREGS) && defined (__x86_64__) + +#define dwarf_register_0(regs) regs->ax +#define dwarf_register_1(regs) regs->dx +#define dwarf_register_2(regs) regs->cx +#define dwarf_register_3(regs) regs->bx +#define dwarf_register_4(regs) regs->si +#define dwarf_register_5(regs) regs->di +#define dwarf_register_6(regs) regs->bp +#define dwarf_register_7(regs) regs->sp +#define dwarf_register_8(regs) regs->r8 +#define dwarf_register_9(regs) regs->r9 +#define dwarf_register_10(regs) regs->r10 +#define dwarf_register_11(regs) regs->r11 +#define dwarf_register_12(regs) regs->r12 +#define dwarf_register_13(regs) regs->r13 +#define dwarf_register_14(regs) regs->r14 +#define dwarf_register_15(regs) regs->r15 + +#elif defined __i386__ /* The stack pointer is unlike other registers. When a trap happens in kernel mode, it is not saved in the trap frame (struct pt_regs). diff --git a/runtime/procfs.c b/runtime/procfs.c index eb0f845c..1b1d5447 100644 --- a/runtime/procfs.c +++ b/runtime/procfs.c @@ -87,8 +87,14 @@ int _stp_mkdir_proc_module(void) goto done; } } else { + #ifdef STAPCONF_NAMEIDATA_CLEANUP + _stp_proc_stap = PDE(nd.path.dentry->d_inode); + path_put (&nd.path); + + #else _stp_proc_stap = PDE(nd.dentry->d_inode); path_release (&nd); + #endif } _stp_proc_root = proc_mkdir(THIS_MODULE->name, _stp_proc_stap); diff --git a/runtime/regs.c b/runtime/regs.c index bc717695..5e08e376 100644 --- a/runtime/regs.c +++ b/runtime/regs.c @@ -33,7 +33,13 @@ unsigned long _stp_ret_addr (struct pt_regs *regs) { -#ifdef __x86_64__ +#if defined (STAPCONF_X86_UNIREGS) && (defined (__x86_64__) || defined (__i386__)) + unsigned long *ra = (unsigned long *)regs->sp; + if (ra) + return *ra; + else + return 0; +#elif defined (__x86_64__) unsigned long *ra = (unsigned long *)regs->rsp; if (ra) return *ra; @@ -77,7 +83,76 @@ unsigned long _stp_ret_addr (struct pt_regs *regs) */ #define _stp_probe_addr_r(ri) (ri->rp->kp.addr) -#ifdef __x86_64__ +#if defined (STAPCONF_X86_UNIREGS) && defined (__x86_64__) + +void _stp_print_regs(struct pt_regs * regs) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; + unsigned int fsindex,gsindex; + unsigned int ds,cs,es; + + _stp_printf("RIP: %016lx\nRSP: %016lx EFLAGS: %08lx\n", regs->ip, regs->sp, regs->flags); + _stp_printf("RAX: %016lx RBX: %016lx RCX: %016lx\n", + regs->ax, regs->bx, regs->cx); + _stp_printf("RDX: %016lx RSI: %016lx RDI: %016lx\n", + regs->dx, regs->si, regs->di); + _stp_printf("RBP: %016lx R08: %016lx R09: %016lx\n", + regs->bp, regs->r8, regs->r9); + _stp_printf("R10: %016lx R11: %016lx R12: %016lx\n", + regs->r10, regs->r11, regs->r12); + _stp_printf("R13: %016lx R14: %016lx R15: %016lx\n", + regs->r13, regs->r14, regs->r15); + + asm("movl %%ds,%0" : "=r" (ds)); + asm("movl %%cs,%0" : "=r" (cs)); + asm("movl %%es,%0" : "=r" (es)); + asm("movl %%fs,%0" : "=r" (fsindex)); + asm("movl %%gs,%0" : "=r" (gsindex)); + + rdmsrl(MSR_FS_BASE, fs); + rdmsrl(MSR_GS_BASE, gs); + rdmsrl(MSR_KERNEL_GS_BASE, shadowgs); + + asm("movq %%cr0, %0": "=r" (cr0)); + asm("movq %%cr2, %0": "=r" (cr2)); + asm("movq %%cr3, %0": "=r" (cr3)); + asm("movq %%cr4, %0": "=r" (cr4)); + + _stp_printf("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n", + fs,fsindex,gs,gsindex,shadowgs); + _stp_printf("CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); + _stp_printf("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4); +} + + #elif defined (STAPCONF_X86_UNIREGS) && defined (__i386__) + +void _stp_print_regs(struct pt_regs * regs) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + + _stp_printf ("EIP: %08lx\n",regs->ip); + _stp_printf ("ESP: %08lx\n",regs->sp); + _stp_printf ("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->ax,regs->bx,regs->cx,regs->dx); + _stp_printf ("ESI: %08lx EDI: %08lx EBP: %08lx", + regs->si, regs->di, regs->bp); + _stp_printf (" DS: %04x ES: %04x\n", + 0xffff & regs->ds,0xffff & regs->es); + + __asm__("movl %%cr0, %0": "=r" (cr0)); + __asm__("movl %%cr2, %0": "=r" (cr2)); + __asm__("movl %%cr3, %0": "=r" (cr3)); + /* This could fault if %cr4 does not exist */ + __asm__("1: movl %%cr4, %0 \n" + "2: \n" + ".section __ex_table,\"a\" \n" + ".long 1b,2b \n" + ".previous \n" + : "=r" (cr4): "0" (0)); + _stp_printf ("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); +} + +#elif defined (__x86_64__) void _stp_print_regs(struct pt_regs * regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs; diff --git a/runtime/regs.h b/runtime/regs.h index 0887d628..c1e2344b 100644 --- a/runtime/regs.h +++ b/runtime/regs.h @@ -11,8 +11,11 @@ #ifndef _REGS_H_ /* -*- linux-c -*- */ #define _REGS_H_ +#if defined (STAPCONF_X86_UNIREGS) && (defined (__x86_64__) || defined (__i386__)) +#define REG_IP(regs) regs->ip +#define REG_SP(regs) regs->sp -#ifdef __x86_64__ +#elif defined (__x86_64__) #define REG_IP(regs) regs->rip #define REG_SP(regs) regs->rsp diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index 3675fc97..d73f4c84 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -21,7 +21,11 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) #ifdef CONFIG_FRAME_POINTER { + #ifdef STAPCONF_X86_UNIREGS + unsigned long ebp = regs->bp; + #elif unsigned long ebp = regs->ebp; + #endif while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { addr = *(unsigned long *)(ebp + 4); diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index 3f373863..53545db2 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,8 @@ +2008-01-21 Martin Hunt <hunt@redhat.com> + + * symbols.c (send_module): Simplify and use new send_data() function to keep + longword alignment. + 2008-01-14 Martin Hunt <hunt@redhat.com> PR4037 and fixes to better synchronize staprun and stapio. diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index ebf05b34..d1bba3f8 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -16,8 +16,6 @@ #include <grp.h> #include <pwd.h> -void cleanup(int rc); - void setup_staprun_signals(void) { struct sigaction a; diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c index 5a4855b3..e33ee624 100644 --- a/runtime/staprun/symbols.c +++ b/runtime/staprun/symbols.c @@ -12,9 +12,8 @@ #include "staprun.h" /* send symbol data */ -static int send_data(void *data, int len) +static int send_data(int32_t type, void *data, int len) { - int32_t type = STP_SYMBOLS; if (write(control_channel, &type, 4) <= 0) return -1; return write(control_channel, data, len); @@ -158,11 +157,9 @@ static int send_module (char *mname) { char data[65536]; int len; - *(int32_t *)data = STP_MODULE; - len = get_sections(mname, data + sizeof(int32_t), - sizeof(data) - sizeof(int32_t)); + len = get_sections(mname, data, sizeof(data)); if (len > 0) { - if (write(control_channel, data, len + sizeof(int32_t)) <= 0) { + if (send_data(STP_MODULE, data, len) < 0) { _err("Loading of module %s failed. Exiting...\n", mname); return -1; } @@ -296,11 +293,11 @@ int do_kernel_symbols(void) goto err; /* send syms */ - if (send_data(syms, num_syms*struct_symbol_size) < 0) + if (send_data(STP_SYMBOLS, syms, num_syms*struct_symbol_size) < 0) goto err; /* send data */ - if (send_data(data_base, dataptr-data_base) < 0) + if (send_data(STP_SYMBOLS, data_base, dataptr-data_base) < 0) goto err; free(data_base); diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 50930709..501c4298 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -42,8 +42,14 @@ #define MAX_SSOL_SLOTS 1024 +#ifdef NO_ACCESS_PROCESS_VM_EXPORT +static int __access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, int write); +#define access_process_vm __access_process_vm +#else extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); +#endif static int utask_fake_quiesce(struct uprobe_task *utask); static void uprobe_release_ssol_vma(struct uprobe_process *uproc); @@ -1601,7 +1607,7 @@ static u32 uprobe_report_signal(struct utrace_attached_engine *engine, int hit_uretprobe_trampoline = 0; int registrations_deferred = 0; - utask = rcu_dereference((struct uprobe_task *)engine->data); + utask = (struct uprobe_task *)rcu_dereference(engine->data); BUG_ON(!utask); if (info->si_signo != BREAKPOINT_SIGNAL && @@ -1785,7 +1791,7 @@ static u32 uprobe_report_quiesce(struct utrace_attached_engine *engine, struct uprobe_task *utask; struct uprobe_process *uproc; - utask = rcu_dereference((struct uprobe_task *)engine->data); + utask = (struct uprobe_task *)rcu_dereference(engine->data); BUG_ON(!utask); uproc = utask->uproc; if (current == utask->quiesce_master) { @@ -1886,7 +1892,7 @@ static u32 uprobe_report_exit(struct utrace_attached_engine *engine, struct uprobe_probept *ppt; int utask_quiescing; - utask = rcu_dereference((struct uprobe_task *)engine->data); + utask = (struct uprobe_task *)rcu_dereference(engine->data); uproc = utask->uproc; uprobe_get_process(uproc); @@ -1965,7 +1971,7 @@ static u32 uprobe_report_clone(struct utrace_attached_engine *engine, struct uprobe_process *uproc; struct uprobe_task *ptask, *ctask; - ptask = rcu_dereference((struct uprobe_task *)engine->data); + ptask = (struct uprobe_task *)rcu_dereference(engine->data); uproc = ptask->uproc; /* @@ -2054,7 +2060,7 @@ static u32 uprobe_report_exec(struct utrace_attached_engine *engine, struct uprobe_task *utask; int uproc_freed; - utask = rcu_dereference((struct uprobe_task *)engine->data); + utask = (struct uprobe_task *)rcu_dereference(engine->data); uproc = utask->uproc; uprobe_get_process(uproc); @@ -2267,5 +2273,61 @@ static void zap_uretprobe_instances(struct uprobe *u, } #endif /* CONFIG_URETPROBES */ +#ifdef NO_ACCESS_PROCESS_VM_EXPORT +/* + * Some kernel versions export everything that uprobes.ko needs except + * access_process_vm, so we copied and pasted it here. Fortunately, + * everything it calls is exported. + */ +#include <linux/pagemap.h> +#include <asm/cacheflush.h> +static int __access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; + + mm = get_task_mm(tsk); + if (!mm) + return 0; + + down_read(&mm->mmap_sem); + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, ret, offset; + void *maddr; + + ret = get_user_pages(tsk, mm, addr, 1, + write, 1, &page, &vma); + if (ret <= 0) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap(page); + if (write) { + copy_to_user_page(vma, page, addr, + maddr + offset, buf, bytes); + set_page_dirty_lock(page); + } else { + copy_from_user_page(vma, page, addr, + buf, maddr + offset, bytes); + } + kunmap(page); + page_cache_release(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + up_read(&mm->mmap_sem); + mmput(mm); + + return buf - old_buf; +} +#endif #include "uprobes_arch.c" MODULE_LICENSE("GPL"); @@ -932,7 +932,14 @@ The location of kernel module building infrastructure. @prefix@/lib/debug/lib/modules/VERSION The location of kernel debugging information when packaged into the .IR kernel\-debuginfo -RPM. +RPM, unless overridden by the +.I SYSTEMTAP_DEBUGINFO_PATH +environment variable. The default value for this variable is +.IR \-:.debug:/usr/lib/debug . +This path is interpreted by elfutils as a list of base directories of +which various subdirectories will be searched. The \- at the front +means to skip CRC matching for separated debug objects and is a small +performance win if no possible corruption is suspected. .TP @prefix@/bin/staprun The auxiliary program supervising module loading, interaction, and diff --git a/staptree.cxx b/staptree.cxx index 8cd9ca83..173314ee 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -18,6 +18,7 @@ #include <cstring> #include <vector> #include <algorithm> +#include <cstring> using namespace std; @@ -89,7 +90,7 @@ probe_point::probe_point (): unsigned probe::last_probeidx = 0; probe::probe (): - body (0), tok (0), condition (0) + body (0), tok (0) { this->name = string ("probe_") + lex_cast<string>(last_probeidx ++); } @@ -899,26 +900,6 @@ probe::collect_derivation_chain (std::vector<derived_probe*> &probes_list) probes_list.push_back((derived_probe*)this); } -void -probe::add_condition (expression* e) -{ - if (e) - { - if (this->condition) - { - logical_and_expr *la = new logical_and_expr (); - la->op = "&&"; - la->left = this->condition; - la->right = e; - la->tok = e->tok; - this->condition = la; - } - else - { - this->condition = e; - } - } -} void probe_point::print (ostream& o) const { @@ -2390,3 +2371,30 @@ deep_copy_visitor::deep_copy (expression* s) require <expression*> (&v, &n, s); return n; } + +template <> void +require <indexable *> (deep_copy_visitor* v, indexable** dst, indexable* src) +{ + if (src != NULL) + { + symbol *array_src=NULL, *array_dst=NULL; + hist_op *hist_src=NULL, *hist_dst=NULL; + + classify_indexable(src, array_src, hist_src); + + *dst = NULL; + + if (array_src) + { + require <symbol*> (v, &array_dst, array_src); + *dst = array_dst; + } + else + { + require <hist_op*> (v, &hist_dst, hist_src); + *dst = hist_dst; + } + assert (*dst); + } +} + @@ -591,10 +591,8 @@ struct probe const token* tok; std::vector<vardecl*> locals; std::vector<vardecl*> unused_locals; - expression* condition; probe (); void print (std::ostream& o) const; - void add_condition (expression* e); virtual void printsig (std::ostream &o) const; virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list); virtual probe* basest () { return this; } @@ -848,31 +846,8 @@ require (deep_copy_visitor* v, T* dst, T src) } } -template <> static void -require <indexable *> (deep_copy_visitor* v, indexable** dst, indexable* src) -{ - if (src != NULL) - { - symbol *array_src=NULL, *array_dst=NULL; - hist_op *hist_src=NULL, *hist_dst=NULL; - - classify_indexable(src, array_src, hist_src); - - *dst = NULL; - - if (array_src) - { - require <symbol*> (v, &array_dst, array_src); - *dst = array_dst; - } - else - { - require <hist_op*> (v, &hist_dst, hist_src); - *dst = hist_dst; - } - assert (*dst); - } -} +template <> void +require <indexable *> (deep_copy_visitor* v, indexable** dst, indexable* src); template <typename T> void provide (deep_copy_visitor* v, T src) diff --git a/systemtap.spec.in b/systemtap.spec.in index 21acffc0..e2f93056 100644 --- a/systemtap.spec.in +++ b/systemtap.spec.in @@ -1,5 +1,5 @@ # Release number for rpm build. Stays at 1 for new PACKAGE_VERSION increases. -%define release 2 +%define release 1 # Version number of oldest elfutils release that works with systemtap. %define elfutils_version 0.127 @@ -51,6 +51,9 @@ BuildRequires: libcap-devel BuildRequires: sqlite-devel Requires: sqlite %endif +%if "%rhel" >= "5" +BuildRequires: crash-devel +%endif # Requires: kernel-devel # or is that kernel-smp-devel? kernel-hugemem-devel? Requires: gcc make @@ -124,9 +127,11 @@ cd .. %define elfutils_mflags LD_LIBRARY_PATH=`pwd`/lib-elfutils %endif +# Enable/disable the sqlite coverage testing support %if %{sqlite} -# Include the coverage testing support -%define sqlite_config --enable-sqlitedb +%define sqlite_config --enable-sqlite +%else +%define sqlite_config --disable-sqlite %endif %configure %{?elfutils_config} %{?sqlite_config} @@ -197,6 +202,10 @@ exit 0 %changelog +* Fri Jan 18 2008 Frank Ch. Eigler <fche@redhat.com> - 0.6.1-1 +- Add crash-devel buildreq to build staplog.so crash(8) module. +- Many robustness & functionality improvements: + * Wed Dec 5 2007 Will Cohen <wcohen@redhat.com> - 0.6-2 - Correct Source to point to location contain code. diff --git a/tapset/ChangeLog b/tapset/ChangeLog index a7f8fdf8..f617b331 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,10 @@ +2008-01-23 Masami Hiramatsu <mhiramat@redhat.com> + + PR5554 + * syscalls.stp (__is_user_regs): Add new function to check whether + pt_regs is user mode registers. + (syscall.fork): Use __is_user_regs() to decide syscall name. + 2008-01-16 Eugene Teo <eteo@redhat.com> * signal.stp (get_sa_flags, get_sa_handler): New functions to diff --git a/tapset/syscalls.stp b/tapset/syscalls.stp index 500aff1a..3a239245 100644 --- a/tapset/syscalls.stp +++ b/tapset/syscalls.stp @@ -848,6 +848,37 @@ probe syscall.flock.return = kernel.function("sys_flock").return { retstr = returnstr(1) } +function __is_user_regs:long (regs:long) %{ /* pure */ + struct pt_regs * regs = (void *)((unsigned long)THIS->regs); +/* copied from asm/ptrace.h */ +#if defined(__i386__) +#ifdef STAPCONF_X86_UNIREGS + int cs = kread(®s->cs); +#else + int cs = kread(®s->xcs); +#endif + THIS->__retvalue = ((cs & SEGMENT_RPL_MASK) == USER_RPL); +#elif defined(__x86_64__) + unsigned long cs = kread(®s->cs); + THIS->__retvalue = (!!((cs & 3))); +#elif defined(__ia64__) + unsigned long psr = kread(®s->cr_ipsr); + THIS->__retvalue = (((struct ia64_psr *) &psr)->cpl != 0); +#elif defined(__powerpc64__) + unsigned long msr = kread(®s->msr); + THIS->__retvalue = ((msr >> MSR_PR_LG) & 0x1); +#elif defined(__arm__) + long cpsr = kread(®s->ARM_cpsr); + THIS->__retvalue = ((cpsr & 0xf) == 0); +#elif defined(__s390__) || defined(__s390x__) + unsigned long mask = kread(®s->psw.mask); + THIS->__retvalue = ((mask & PSW_MASK_PSTATE) != 0); +#else +#error "Unimplemented architecture" +#endif +CATCH_DEREF_FAULT(); +%} + # fork _______________________________________________________ # long do_fork(unsigned long clone_flags, # unsigned long stack_start, @@ -863,7 +894,7 @@ probe syscall.fork = kernel.function("do_fork") { parent_tid_uaddr = $parent_tidptr child_tid_uaddr = $child_tidptr - if (stack_start == 0) { + if (!__is_user_regs(regs)) { name = "fork_kernel_thread" argstr = __fork_flags(clone_flags) } else if (clone_flags == 17) diff --git a/tapsets.cxx b/tapsets.cxx index 84187960..06aa73aa 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -716,7 +716,10 @@ struct dwflpp { // XXX: this is where the session -R parameter could come in static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug"; - static char *debuginfo_path = debuginfo_path_arr; + static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); + + static char *debuginfo_path = (debuginfo_env_arr ? + debuginfo_env_arr : debuginfo_path_arr); static const Dwfl_Callbacks proc_callbacks = { @@ -3632,7 +3635,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, Dwarf_Addr addr, dwarf_query& q, Dwarf_Die* scope_die /* may be null */) - : derived_probe (q.base_probe, 0 /* location-less */), + : derived_probe (q.base_probe, q.base_loc /* NB: base_loc.components will be overwritten */ ), module (module), section (section), addr (addr), has_return (q.has_return), has_maxactive (q.has_maxactive), @@ -3644,14 +3647,8 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, if (section != "" && dwfl_addr == addr) // addr should be an offset throw semantic_error ("inconsistent relocation address", q.base_loc->tok); - this->tok = q.base_probe->tok; - // add condition from base location - if (q.base_loc->condition) - add_condition (q.base_loc->condition); - insert_condition_statement (); - // Make a target-variable-expanded copy of the probe body if (scope_die) { @@ -3674,7 +3671,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, } // else - null scope_die - $target variables will produce an error during translate phase - // Set the sole element of the "locations" vector as a + // 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 // number any particular match of the wildcards. @@ -3727,7 +3724,8 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, comps.push_back (new probe_point::component (TOK_MAXACTIVE, new literal_number(maxactive_val))); - locations.push_back(new probe_point(comps, q.base_loc->tok)); + // Overwrite it. + this->sole_location()->components = comps; } @@ -4578,6 +4576,8 @@ procfs_derived_probe_group::enroll (procfs_derived_probe* p) throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\""); else if (! p->write && pset->read_probe != NULL) throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\""); + + // XXX: multiple writes should be acceptable } if (p->write) @@ -4970,7 +4970,7 @@ struct mark_derived_probe: public derived_probe { mark_derived_probe (systemtap_session &s, const string& probe_name, const string& probe_sig, - probe* base_probe, expression* cond); + probe* base_probe, probe_point* location); systemtap_session& sess; string probe_name, probe_sig; @@ -5121,24 +5121,15 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) mark_derived_probe::mark_derived_probe (systemtap_session &s, const string& p_n, const string& p_s, - probe* base, expression* cond): - derived_probe (base, 0), sess (s), probe_name (p_n), probe_sig (p_s), + probe* base, probe_point* loc): + derived_probe (base, loc), sess (s), probe_name (p_n), probe_sig (p_s), target_symbol_seen (false) { - // create synthetic probe point - probe_point* pp = new probe_point; - - probe_point::component* c; - c = new probe_point::component ("kernel"); - pp->components.push_back (c); - c = new probe_point::component ("mark", - new literal_string (probe_name)); - pp->components.push_back (c); - this->locations.push_back (pp); - - if (cond) - add_condition (cond); - insert_condition_statement (); + // create synthetic probe point name; preserve condition + vector<probe_point::component*> comps; + comps.push_back (new probe_point::component ("kernel")); + comps.push_back (new probe_point::component ("mark", new literal_string (probe_name))); + this->sole_location()->components = comps; // expand the signature string parse_probe_sig(); @@ -5543,7 +5534,7 @@ mark_builder::build(systemtap_session & sess, derived_probe *dp = new mark_derived_probe (sess, it->first, it->second, - base, loc->condition); + base, loc); finished_results.push_back (dp); } } diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 6dd0d8de..f30b9891 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,29 @@ +2008-01-24 Frank Ch. Eigler <fche@elastic.org> + + crash(8) tests, based on Masami Hiramatsu <mhiramat@redhat.com>: + * Makefile.am (CRASH_LIBDIR): Pass in $(RUNTEST). + * lib/systemtap.exp (as_root): Trace command string, output, and + result. + * sysetmtap.samples/crash.*, testlog.stp: New test case. + * Makefile.in: Regenerated. + +2008-01-23 Frank Ch. Eigler <fche@elastic.org> + + PR 2521. + * systemtap.base/debugpath.exp: New test. + +2008-01-18 Frank Ch. Eigler <fche@elastic.org> + + * configure.ac: Bump version to 0.6.1. + * configure: Regenerated. + +2008-01-17 Frank Ch. Eigler <fche@elastic.org> + + PR 4935. + * semko/forty.stp, fortyone.stp, fortytwo.stp: New tests. + * semok/twentynine.stp: Weaken test since condition expressions have + become more tightly constrained. + 2008-01-17 David Smith <dsmith@redhat.com> * semko/procfs11.stp: Added test for invalid use of procfs probe diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 689ec371..6b14bd60 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = config lib systemtap \ SYSTEMTAP_RUNTIME=$(DESTDIR)$(pkgdatadir)/runtime SYSTEMTAP_TAPSET=$(DESTDIR)$(pkgdatadir)/tapset LD_LIBRARY_PATH=$(DESTDIR)$(libdir)/systemtap +CRASH_LIBDIR=$(DESTDIR)$(libdir)/systemtap SYSTEMTAP_PATH=$(DESTDIR)$(bindir) -RUNTEST="env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" +RUNTEST="env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 3f2db011..8907c519 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -36,7 +36,8 @@ DIST_COMMON = $(am__configure_deps) $(srcdir)/../install-sh \ $(srcdir)/../missing $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/configure ../AUTHORS \ ../COPYING ../ChangeLog ../INSTALL ../NEWS ../README \ - ../compile ../depcomp ../install-sh ../missing ChangeLog + ../compile ../config.guess ../depcomp ../install-sh ../missing \ + ChangeLog ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -146,8 +147,9 @@ EXTRA_DIST = config lib systemtap \ SYSTEMTAP_RUNTIME = $(DESTDIR)$(pkgdatadir)/runtime SYSTEMTAP_TAPSET = $(DESTDIR)$(pkgdatadir)/tapset LD_LIBRARY_PATH = $(DESTDIR)$(libdir)/systemtap +CRASH_LIBDIR = $(DESTDIR)$(libdir)/systemtap SYSTEMTAP_PATH = $(DESTDIR)$(bindir) -RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" +RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" all: all-am .SUFFIXES: diff --git a/testsuite/configure b/testsuite/configure index e50dc588..2e29a3d7 100755 --- a/testsuite/configure +++ b/testsuite/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for systemtap 0.6. +# Generated by GNU Autoconf 2.61 for systemtap 0.6.1. # # Report bugs to <systemtap@sources.redhat.com>. # @@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='systemtap' PACKAGE_TARNAME='systemtap' -PACKAGE_VERSION='0.6' -PACKAGE_STRING='systemtap 0.6' +PACKAGE_VERSION='0.6.1' +PACKAGE_STRING='systemtap 0.6.1' PACKAGE_BUGREPORT='systemtap@sources.redhat.com' ac_subst_vars='SHELL @@ -1148,7 +1148,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures systemtap 0.6 to adapt to many kinds of systems. +\`configure' configures systemtap 0.6.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1214,7 +1214,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of systemtap 0.6:";; + short | recursive ) echo "Configuration of systemtap 0.6.1:";; esac cat <<\_ACEOF @@ -1285,7 +1285,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -systemtap configure 0.6 +systemtap configure 0.6.1 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1299,7 +1299,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by systemtap $as_me 0.6, which was +It was created by systemtap $as_me 0.6.1, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -1991,7 +1991,7 @@ fi # Define the identity of the package. PACKAGE='systemtap' - VERSION='0.6' + VERSION='0.6.1' cat >>confdefs.h <<_ACEOF @@ -2595,7 +2595,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by systemtap $as_me 0.6, which was +This file was extended by systemtap $as_me 0.6.1, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -2638,7 +2638,7 @@ Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -systemtap config.status 0.6 +systemtap config.status 0.6.1 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/testsuite/configure.ac b/testsuite/configure.ac index 18e85559..5eb9b151 100644 --- a/testsuite/configure.ac +++ b/testsuite/configure.ac @@ -1,7 +1,7 @@ dnl configure.ac --- autoconf input file for systemtap testsuite dnl Process this file with autoconf to produce a configure script. -AC_INIT([systemtap], 0.6, systemtap@sources.redhat.com, systemtap) +AC_INIT([systemtap], 0.6.1, systemtap@sources.redhat.com, systemtap) AC_PREREQ(2.59) AC_CONFIG_AUX_DIR(..) diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index f677da41..baed0e41 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -121,6 +121,9 @@ proc as_root { command } { if {$effective_pid != 0} { set command "sudo $command" } + verbose -log "as_root $command" set res [catch {eval exec $command} value] + verbose -log "OUT $value" + verbose -log "RC $res" return $res } diff --git a/testsuite/semko/forty.stp b/testsuite/semko/forty.stp new file mode 100755 index 00000000..f7721a47 --- /dev/null +++ b/testsuite/semko/forty.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +global x +probe kernel.function("sys_open") if (x = 1) { } # bad side-effect diff --git a/testsuite/semko/fortyone.stp b/testsuite/semko/fortyone.stp new file mode 100755 index 00000000..e9b986df --- /dev/null +++ b/testsuite/semko/fortyone.stp @@ -0,0 +1,3 @@ +#! stap -p2 + +probe kernel.function("sys_open") if (x > 1) { } # not a global diff --git a/testsuite/semko/fortytwo.stp b/testsuite/semko/fortytwo.stp new file mode 100755 index 00000000..17dacb1c --- /dev/null +++ b/testsuite/semko/fortytwo.stp @@ -0,0 +1,10 @@ +#! stap -p2 + +probe kernel.function("sys_open") if (foo(2)) { } # must not call functions + +function foo(x) { return x } + +# NB: If this condition is relaxed, then this will have to be blocked: +# global y function foo () { return y++ } # since global y is written-to +# but this one would be fine: +# function foo () { return y++ } # since y is written-to diff --git a/testsuite/semok/twentynine.stp b/testsuite/semok/twentynine.stp index 6fe308f2..05e591ce 100644 --- a/testsuite/semok/twentynine.stp +++ b/testsuite/semok/twentynine.stp @@ -4,10 +4,10 @@ function dummy:long () {return p;} # alias with a condition probe alias0 = begin if (3) {p=1} -# alias with a kernel-variable condition -probe alias1 = kernel.function("sys_read").return if ($return) {p=0} +# alias with a kernel-variable condition -- not valid +probe alias1 = kernel.function("sys_read").return if (0) { if ($return) {p=0} } # alias with a function-call condition -probe blias0 = timer.s(1) if (dummy()) {p=10} +probe blias0 = timer.s(1) if (1 /* dummy() */) {p=10} # multiple probe point with conditions probe alias2 = alias0 if (1), alias1 if (-1) {p=2} diff --git a/testsuite/systemtap.base/debugpath.exp b/testsuite/systemtap.base/debugpath.exp new file mode 100644 index 00000000..67b9eb70 --- /dev/null +++ b/testsuite/systemtap.base/debugpath.exp @@ -0,0 +1,18 @@ + +set test "debugpath-bad" +spawn env SYSTEMTAP_DEBUGINFO_PATH=/dev/null stap -e "probe kernel.function(\"sys_open\") {}" -p4 +expect { + -re {^semantic error:.*missing.*debuginfo} { pass $test } + timeout { fail "$test (timeout1)" } + eof { fail "$test (eof)" } +} +catch { close; wait } + +set test "debugpath-good" +spawn env SYSTEMTAP_DEBUGINFO_PATH=:/usr/lib/debug stap -e "probe kernel.function(\"sys_open\") {}" -p2 +expect { + -re {kernel.function.*pc=} { pass $test } + timeout { fail "$test (timeout2)" } + eof { fail "$test (eof)" } +} +catch { close ; wait } diff --git a/testsuite/systemtap.samples/crash.exp b/testsuite/systemtap.samples/crash.exp new file mode 100644 index 00000000..629cff54 --- /dev/null +++ b/testsuite/systemtap.samples/crash.exp @@ -0,0 +1,45 @@ +# Simple test for staplog.so crash(8) extension +set test "crash" + +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 +expect { + -timeout 120 + "HelloWorld\r\n" { + pass "$test - testlog.stp" + # Need to run crash(8) while this script is still running. + # Since crash(8) needs /dev/mem access, need it run as_root too. + # This [ eval ... \{ \} ] business is necessary because as_root + # evals the given list/variables in its own scope. + eval as_root \{ $srcdir/$subdir/crash.sh $env(CRASH_LIBDIR) \} + } + timeout { fail "$test - testlog.stp timeout" } + timeout { fail "$test - testlog.stp eof" } +} +catch { send "\003"; close ; wait } + +# The crash(8) script creates testlog/global or testlog/cpu<n> +as_root { chmod -R a+rX testlog } + +set ok 0 +foreach f [glob -nocomplain testlog/*] { + pass "$test - crash(8) generated $f" + set fp [open $f] + set chars [read $fp] + close $fp + if [string match "HelloWorld*" $chars] { + incr ok + pass "$test - crash(8) data" + } else { + fail "$test - crash(8) data $chars" + } +} +if {$ok == 0} { + fail "$test - crash(8) data" +} + +as_root { rm -rf testlog testlog.ko } + diff --git a/testsuite/systemtap.samples/crash.sh b/testsuite/systemtap.samples/crash.sh new file mode 100755 index 00000000..06aa414e --- /dev/null +++ b/testsuite/systemtap.samples/crash.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +crash --readnow << END +mod -s testlog testlog.ko +extend $1/staplog.so +staplog testlog +exit +END diff --git a/testsuite/systemtap.samples/testlog.stp b/testsuite/systemtap.samples/testlog.stp new file mode 100644 index 00000000..5b702aa9 --- /dev/null +++ b/testsuite/systemtap.samples/testlog.stp @@ -0,0 +1,6 @@ +probe begin +{ + printf("Hello"); + printf("World"); + printf("\n"); +} diff --git a/translate.cxx b/translate.cxx index 7f42ceec..0beaf1f8 100644 --- a/translate.cxx +++ b/translate.cxx @@ -400,6 +400,20 @@ public: } } + string fini () const + { + switch (type()) + { + case pe_string: + case pe_long: + return ""; // no action required + case pe_stats: + return "_stp_stat_del (" + value () + ");"; + default: + throw semantic_error("unsupported deallocator for " + value()); + } + } + void declare(c_unparser &c) const { c.c_declare(ty, name); @@ -887,8 +901,12 @@ c_unparser::emit_common_header () // NB: see c_unparser::emit_probe() for original copy of duplicate-hashing logic. ostringstream oss; oss << "c->statp = & time_" << dp->basest()->name << ";" << endl; // -t anti-dupe - dp->body->print(oss); oss << "# needs_global_locks: " << dp->needs_global_locks () << endl; + dp->body->print(oss); + // NB: dependent probe conditions *could* be listed here, but don't need to be. + // That's because they're only dependent on the probe body, which is already + // "hashed" in above. + if (tmp_probe_contents.count(oss.str()) == 0) // unique { @@ -911,9 +929,13 @@ c_unparser::emit_common_header () throw e2; } } + + // NB: This part is finicky. The logic here must + // match up with c_tmpcounter ct (this); - dp->body->visit (& ct); dp->emit_probe_context_vars (o); + dp->body->visit (& ct); + o->newline(-1) << "} " << dp->name << ";"; } } @@ -1193,6 +1215,8 @@ c_unparser::emit_module_init () vardecl* v = session->globals[i]; if (v->index_types.size() > 0) o->newline() << getmap (v).fini(); + else + o->newline() << getvar (v).fini(); } o->newline() << "return rc;"; @@ -1254,6 +1278,8 @@ c_unparser::emit_module_exit () vardecl* v = session->globals[i]; if (v->index_types.size() > 0) o->newline() << getmap (v).fini(); + else + o->newline() << getvar (v).fini(); } o->newline() << "free_percpu (contexts);"; @@ -1404,8 +1430,11 @@ c_unparser::emit_probe (derived_probe* v) // // which would make comparisons impossible. // - // NB: see also c_unparser:emit_common_header(), which duplicates - // this calculation. + // -------------------------------------------------------------------------- + // NB: see also c_unparser:emit_common_header(), which deliberately but sadly + // duplicates this calculation. + // -------------------------------------------------------------------------- + // ostringstream oss; // NB: statp is just for avoiding designation as duplicate. It need not be C. @@ -1503,13 +1532,12 @@ c_unparser::emit_probe (derived_probe* v) } v->initialize_probe_context_vars (o); - + v->body->visit (this); o->newline(-1) << "out:"; - // NB: no need to uninitialize locals, except if arrays can - // somedays be local - + // NB: no need to uninitialize locals, except if arrays/stats can + // someday be local // XXX: do this flush only if the body included a // print/printf/etc. routine! |