From c931ec8ab64f5b6667e28b0f64338643d4b9ed03 Mon Sep 17 00:00:00 2001 From: fche Date: Sun, 26 Nov 2006 23:28:15 +0000 Subject: 2006-11-26 Frank Ch. Eigler PRs 2685, 3596, toward 2725. * tapsets.cxx (common_probe_entryfn_prologue): Skip probe on insufficient stack. (build_blacklist): Add a slew of lock-related calls. (query_module): Check for debuginfo architecture match. * translate.cxx (translate_pass): Add default MINSTACKSPACE. * configure.ac: Link stap with -lebl too. * configure: Regenerated. * stap.1.in: Document MINSTACKSPACE parameter. --- ChangeLog | 12 +++++++++ configure | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 5 +++- stap.1.in | 7 ++++- tapsets.cxx | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++--- translate.cxx | 3 +++ 6 files changed, 179 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1fe67b59..c71a8c27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-11-26 Frank Ch. Eigler + + PRs 2685, 3596, toward 2725. + * tapsets.cxx (common_probe_entryfn_prologue): Skip probe on + insufficient stack. + (build_blacklist): Add a slew of lock-related calls. + (query_module): Check for debuginfo architecture match. + * translate.cxx (translate_pass): Add default MINSTACKSPACE. + * configure.ac: Link stap with -lebl too. + * configure: Regenerated. + * stap.1.in: Document MINSTACKSPACE parameter. + 2006-11-21 Frank Ch. Eigler * translate.cxx (emit_module_init): Adapt to 2.6.19 utsname(). diff --git a/configure b/configure index 240df784..7cee7614 100755 --- a/configure +++ b/configure @@ -5852,6 +5852,85 @@ _ACEOF LIBS="-ldw $LIBS" +else + + { { echo "$as_me:$LINENO: error: systemtap requires elfutils 0.123+" >&5 +echo "$as_me: error: systemtap requires elfutils 0.123+" >&2;} + { (exit 1); exit 1; }; } +fi + + +echo "$as_me:$LINENO: checking for ebl_openbackend in -lebl" >&5 +echo $ECHO_N "checking for ebl_openbackend in -lebl... $ECHO_C" >&6 +if test "${ac_cv_lib_ebl_ebl_openbackend+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lebl $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 gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ebl_openbackend (); +int +main () +{ +ebl_openbackend (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&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); } && + { ac_try='test -z "$ac_cxx_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ebl_ebl_openbackend=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ebl_ebl_openbackend=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ebl_ebl_openbackend" >&5 +echo "${ECHO_T}$ac_cv_lib_ebl_ebl_openbackend" >&6 +if test $ac_cv_lib_ebl_ebl_openbackend = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBEBL 1 +_ACEOF + + LIBS="-lebl $LIBS" + else { { echo "$as_me:$LINENO: error: systemtap requires elfutils 0.123+" >&5 @@ -5863,9 +5942,11 @@ fi LIBS="$SAVE_LIBS" else # We built our own and stap_LDFLAGS points at the install. - stap_LIBS=-ldw + stap_LIBS="-ldw -lebl" fi +{ echo "$as_me:$LINENO: stap will link $stap_LIBS" >&5 +echo "$as_me: stap will link $stap_LIBS" >&6;} date=`date +%Y-%m-%d` diff --git a/configure.ac b/configure.ac index 5ff48549..ea3b61da 100644 --- a/configure.ac +++ b/configure.ac @@ -101,13 +101,16 @@ if test $build_elfutils = no; then save_LIBS="$LIBS" AC_CHECK_LIB(dw, dwfl_module_getsym,,[ AC_MSG_ERROR([systemtap requires elfutils 0.123+])]) + AC_CHECK_LIB(ebl, ebl_openbackend,,[ + AC_MSG_ERROR([systemtap requires elfutils 0.123+])]) stap_LIBS="$LIBS" LIBS="$SAVE_LIBS" else # We built our own and stap_LDFLAGS points at the install. - stap_LIBS=-ldw + stap_LIBS="-ldw -lebl" fi AC_SUBST(stap_LIBS) +AC_MSG_NOTICE([stap will link $stap_LIBS]) dnl Plop in the build (configure) date date=`date +%Y-%m-%d` diff --git a/stap.1.in b/stap.1.in index 5b5cd3e6..3986c52b 100644 --- a/stap.1.in +++ b/stap.1.in @@ -746,7 +746,7 @@ script is translated again assuming the same conditions exist (same kernel version, same systemtap version, etc.). Cached files are stored in the .I $SYSTEMTAP_DIR/cache -directory. +directory, which may be periodically cleaned/erased by the user. .SH SAFETY AND SECURITY Systemtap is an administrative tool. It exposes kernel internal data @@ -801,6 +801,11 @@ means that the first error will exit the script. .TP MAXSKIPPED Maximum number of skipped reentrant probes before an exit is triggered, default 100. +.TP +MINSTACKSPACE +Minimum number of free kernel stack bytes required in order to +run a probe handler, default 1024. This number should be large enough +for the probe handler's own needs, plus a safety margin. .PP In case something goes wrong with diff --git a/tapsets.cxx b/tapsets.cxx index 55a53cca..852ef378 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -29,6 +29,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -174,6 +175,16 @@ common_probe_entryfn_prologue (translator_output* o, string statestr) o->newline() << "local_irq_save (flags);"; + // Check for enough free enough stack space + o->newline() << "if ((((unsigned long) (& c)) & (THREAD_SIZE-1))"; + o->newline(1) << "< (THREAD_SIZE - MINSTACKSPACE - sizeof (struct task_struct))) {"; + o->newline() << "if (atomic_inc_return (& skipped_count) > MAXSKIPPED) {"; + o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "_stp_exit ();"; + o->newline(-1) << "}"; + o->newline() << "goto probe_epilogue;"; + o->newline(-1) << "}"; + o->newline() << "if (atomic_read (&session_state) != " << statestr << ")"; o->newline(1) << "goto probe_epilogue;"; o->indent(-1); @@ -717,7 +728,7 @@ struct dwflpp // NB: "rc == 0" means OK in this case - void dwfl_assert(string desc, int rc, string extra_msg = "") + static void dwfl_assert(string desc, int rc, string extra_msg = "") { string msg = "libdwfl failure (" + desc + "): "; if (rc < 0) msg += dwfl_errmsg (rc); @@ -2037,6 +2048,18 @@ dwarf_query::build_blacklist() blacklisted_probes.insert("unhandled_fault"); blacklisted_probes.insert("unknown_nmi_error"); + blacklisted_probes.insert("_read_trylock"); + blacklisted_probes.insert("_read_lock"); + blacklisted_probes.insert("_read_unlock"); + blacklisted_probes.insert("_write_trylock"); + blacklisted_probes.insert("_write_lock"); + blacklisted_probes.insert("_write_unlock"); + blacklisted_probes.insert("_spin_lock"); + blacklisted_probes.insert("_spin_lock_irqsave"); + blacklisted_probes.insert("_spin_trylock"); + blacklisted_probes.insert("_spin_unlock"); + blacklisted_probes.insert("_spin_unlock_irqrestore"); + // __switch_to is only disallowed on x86_64 if (sess.architecture == "x86_64") blacklisted_probes.insert("__switch_to"); @@ -2748,11 +2771,57 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)), if (q->has_module && !q->dw.module_name_matches(q->module_val)) return DWARF_CB_OK; + // Validate the machine code in this elf file against the + // session machine. This is important, in case the wrong kind + // of debuginfo is being automagically processed by elfutils. + // Unfortunately, while we can tell i686 apart from x86-64, + // we can't help confusing i586 vs i686 (both EM_386). + + Dwarf_Addr _junk; + Elf* elf = dwfl_module_getelf (mod, &_junk); + Ebl* ebl = ebl_openbackend (elf); + int elf_machine = ebl_get_elfmachine (ebl); + const char* debug_filename = ""; + const char* main_filename = ""; + (void) dwfl_module_info (mod, NULL, NULL, + NULL, NULL, NULL, + & main_filename, + & debug_filename); + const string& sess_machine = q->sess.architecture; + string expect_machine; + switch (elf_machine) + { + case EM_386: expect_machine = "i686"; break; + case EM_X86_64: expect_machine = "x86_64"; break; + case EM_PPC: expect_machine = "ppc"; break; + case EM_PPC64: expect_machine = "ppc64"; break; + case EM_S390: expect_machine = "s390x"; break; + case EM_IA_64: expect_machine = "ia64"; break; + // XXX: fill in some more of these + default: expect_machine = "?"; break; + } + + if (! debug_filename) debug_filename = main_filename; + if (! debug_filename) debug_filename = name; + + if (sess_machine != expect_machine) + { + stringstream msg; + msg << "ELF machine " << expect_machine << " (code " << elf_machine + << ") mismatch with target " << sess_machine + << " in '" << debug_filename << "'"; + throw semantic_error(msg.str ()); + } + if (q->sess.verbose>2) clog << "focused on module '" << q->dw.module_name - << "' = [" << hex << q->dw.module_start + << " = [" << hex << q->dw.module_start << "-" << q->dw.module_end - << ", bias " << q->dw.module_bias << "]" << dec << "\n"; + << ", bias " << q->dw.module_bias << "]" << dec + << " file " << debug_filename + << " ELF machine " << expect_machine + << " (code " << elf_machine << ")" + << "\n"; if (q->has_inline_num || q->has_function_num || q->has_statement_num) { diff --git a/translate.cxx b/translate.cxx index 09c51a6e..f36280da 100644 --- a/translate.cxx +++ b/translate.cxx @@ -3984,6 +3984,9 @@ translate_pass (systemtap_session& s) s.op->newline() << "#ifndef MAXSKIPPED"; s.op->newline() << "#define MAXSKIPPED 100"; s.op->newline() << "#endif"; + s.op->newline() << "#ifndef MINSTACKSPACE"; + s.op->newline() << "#define MINSTACKSPACE 1024"; + s.op->newline() << "#endif"; // impedance mismatch // STP_STRING_SIZE defines the size of the buffer -- cgit