diff options
42 files changed, 758 insertions, 123 deletions
@@ -1,3 +1,75 @@ +2008-03-27 Frank Ch. Eigler <fche@elastic.org> + + * tapsets.cxx (common_probe_entryfn_prologue): Clear last_stmt. + +2008-03-26 Frank Ch. Eigler <fche@elastic.org> + + * translate.cxx (emit_function): Set context last_stmt, in case + an error occurs during the function. + +2008-03-25 Frank Ch. Eigler <fche@elastic.org> + + * stap.1.in: Clarify utility of epilogue type probe aliases. + +2008-03-21 Eugene Teo <eugeneteo@kernel.sg> + + PR 5528 + * tapset/conversions.stp (user_string_n, user_string_n2, + user_string_n_warn, user_string_n_quoted, user_short, user_short_warn, + user_int, user_int_warn, user_long, user_long_warn, user_char, + user_char_warn): New user_* functions. + * stapfuncs.5.in: Documented the new functions. + * testsuite/systemtap.stress/conversions.stp: Test new functions. + * testsuite/buildok/conversions.stp: Test new functions. + * testsuite/buildok/conversions-embedded.stp: Test new functions. + +2008-03-20 Frank Ch. Eigler <fche@elastic.org> + + PR 5975. + * tapsets.cxx (*): Added a few (void) expressions for asserts that + may be compiled out. + +2008-03-14 Masami Hiramatsu <mhiramat@redhat.com> + + PR 3542 + * buildrun.cxx (compile_pass): Add an autoconf to check the kernel + supports batch unregistration. + * tapsets.cxx (dwarf_derived_probe_group::emit_module_decls): Add an + array of probe pointers for batch unregistration. + * tapsets.cxx (dwarf_derived_probe_group::emit_module_exit): Use + unregister_k(ret)probes if it is supported. + +2008-03-13 Frank Ch. Eigler <fche@elastic.org> + + PR 5928. + * buildrun.cxx (compile_pass): Use EXTRA_CFLAGS for autoconf'd values + instead of CFLAGS_<module>.o. + +2008-03-12 Frank Ch. Eigler <fche@elastic.org> + + * configure.ac, systemtap.spec.in: Bumped version to 0.6.2. + * configure: Regenerated. + +2008-03-12 Dave Brolley <brolley@redhat.com> + + PR5897 + * staptree.cxx (probe::printsig): If this probe was derived from an alias, + call the printsig method of the alias. + +2008-03-10 Dave Brolley <brolley@redhat.com> + + PR5189 + * translate.cxx (probe_or_function_needs_deref_fault_handler): New member of + c_unparser. + (c_unparser::emit_function): Initialize probe_or_function_needs_deref_fault_handler. + Check it after the body is visited and generate a deref fault handler if necessary. + (c_unparser::emit_probe): Likewise. + (c_unparser::visit_print_format): Correct the compoenent type for an overridden string + literal. Generate code to check that pointer arguments to %m can be dereferenced. + Generate casts for printf arguments as necessary. + * elaborate.cxx (typeresolution_info::visit_print_format): Desired type for conv_memory + is pe_long. + 2008-03-06 Frank Ch. Eigler <fche@elastic.org> * Makefile.am (AM_CXXFLAGS, AM_CFLAGS): Remove -Werror. @@ -1,4 +1,7 @@ -* What's new in version 0.6 / 0.6.1 +* What's new in version 0.6 + +- A copy of the systemtap tutorial and language reference guide + are now included. - There is a new format specifier, %m, for the printf family of functions. It functions like %s, except that it does not stop when diff --git a/README.security b/README.security index 62728068..323840f6 100644 --- a/README.security +++ b/README.security @@ -4,7 +4,7 @@ system, root access is needed. SECURITY MODEL ============== -Originally sudo(8) was used to grant root acess. After compiling a +Originally sudo(8) was used to grant root access. After compiling a new kernel module, stap ran "sudo staprun module_path". This worked, but required all systemtap users to have root access. Many sysadmins on enterprise systems do not have root access. @@ -22,7 +22,7 @@ following: directory (where VERSION is the output of "uname -r"). This directory must be owned by root and not be world writable. -So, there are two classes of users: systemap developers (the root user +So, there are two classes of users: systemtap developers (the root user and members of the stapdev group) and systemtap users (members of the stapusr group). Systemtap developers can compile and run any systemtap script. Systemtap users can only run "approved" @@ -53,7 +53,7 @@ On the development machine: the script may need to be edited to fix any errors.) # scp pmod.ko prod_machine:/lib/modules/`uname -r`/systemtap -(The systemtap develop copies the compiled kernel module to the proper +(The systemtap developer copies the compiled kernel module to the proper directory on the production machine. Of course other methods - ftp, nfs, etc. could be used to transfer the module.) @@ -64,7 +64,7 @@ $ staprun pmod There are (at least) 2 different usage scenarios for the /lib/modules/VERSION/systemtap directory. -1) Most restrictive useage. If only root should be able to able to +1) Most restrictive usage. If only root should be able to able to add "approved" systemtap modules to /lib/modules/VERSION/systemtap, the permissions should be 755, like this: @@ -88,7 +88,7 @@ program is a setuid program that does some system setup, loads the kernel module, then runs stapio (and waits for it to finish). The stapio program runs as the invoking user and is responsible for all communication with the kernel module. After the script runs to -completion, stapio exits and staprun unloads the kermel module. +completion, stapio exits and staprun unloads the kernel module. staprun is a setuid program that uses POSIX capabilities. Using POSIX capabilities allows the program to only have the privileges to do @@ -104,7 +104,7 @@ invoking user: The above capabilities are the permitted set of capabilities for staprun, which is the list of all the capabilities staprun is ever -permitted to have. In addition, the effective set of capabilites, the +permitted to have. In addition, the effective set of capabilities, the capabilities from the permitted set that are currently enabled, is cleared. When needed, a particular capability is enabled, the operation is performed, then the capability is disabled. The staprun diff --git a/buildrun.cxx b/buildrun.cxx index f3f29d49..f3e72272 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -74,16 +74,18 @@ compile_pass (systemtap_session& s) // Create makefile // Clever hacks copied from vmware modules - o << "stap_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl; - o << "stap_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\" -Werror -S -o /dev/null -xc $(1) > /dev/null 2>&1 ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl; + string superverbose; + if (s.verbose > 3) + superverbose = "set -x;"; + o << "stap_check_gcc = $(shell " << superverbose << " if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl; + o << "stap_check_build = $(shell " << superverbose << " if $(CC) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\" -Werror -S -o /dev/null -xc $(1) > /dev/null 2>&1 ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl; o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl; // "autoconf" options go here - // enum hrtimer_mode renaming near 2.6.21; see tapsets.cxx hrtimer_derived_probe_group::emit_module_decls - string module_cflags = "CFLAGS_" + s.module_name + ".o"; + string module_cflags = "EXTRA_CFLAGS"; o << module_cflags << " :=" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-hrtimer-rel.c, -DSTAPCONF_HRTIMER_REL,)" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-inode-private.c, -DSTAPCONF_INODE_PRIVATE,)" << endl; @@ -93,6 +95,7 @@ compile_pass (systemtap_session& s) 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; + o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-unregister-kprobes.c, -DSTAPCONF_UNREGISTER_KPROBES,)" << 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.1. +# Generated by GNU Autoconf 2.61 for systemtap 0.6.2. # # 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.1' -PACKAGE_STRING='systemtap 0.6.1' +PACKAGE_VERSION='0.6.2' +PACKAGE_STRING='systemtap 0.6.2' PACKAGE_BUGREPORT='systemtap@sources.redhat.com' # Factoring default headers for most tests. @@ -1240,7 +1240,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.1 to adapt to many kinds of systems. +\`configure' configures systemtap 0.6.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1306,7 +1306,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of systemtap 0.6.1:";; + short | recursive ) echo "Configuration of systemtap 0.6.2:";; esac cat <<\_ACEOF @@ -1415,7 +1415,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -systemtap configure 0.6.1 +systemtap configure 0.6.2 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1429,7 +1429,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.1, which was +It was created by systemtap $as_me 0.6.2, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -2121,7 +2121,7 @@ fi # Define the identity of the package. PACKAGE='systemtap' - VERSION='0.6.1' + VERSION='0.6.2' cat >>confdefs.h <<_ACEOF @@ -7278,7 +7278,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.1, which was +This file was extended by systemtap $as_me 0.6.2, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7331,7 +7331,7 @@ Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -systemtap config.status 0.6.1 +systemtap config.status 0.6.2 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 93a0327f..f343faef 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl configure.ac --- autoconf input file for systemtap dnl Process this file with autoconf to produce a configure script. -AC_INIT([systemtap], 0.6.1, systemtap@sources.redhat.com, systemtap) +AC_INIT([systemtap], 0.6.2, systemtap@sources.redhat.com, systemtap) dnl ^^^ see also NEWS, testsuite/configure.ac AC_PREREQ(2.59) diff --git a/doc/ChangeLog b/doc/ChangeLog index 902e1d1e..e652078d 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2008-03-25 Frank Ch. Eigler <fche@elastic.org> + + * langref.tex: Clarify utility of epilogue-type probe aliases. + 2008-03-04 David Smith <dsmith@redhat.com> * tutorial.tex: Made minor changes to remove warnings. diff --git a/doc/langref.tex b/doc/langref.tex index 5b91d01d..973769d4 100644 --- a/doc/langref.tex +++ b/doc/langref.tex @@ -230,7 +230,7 @@ This prints: \end{verbatim} \end{vindent} Any larger number input to the function may exceed the MAXACTION or MAXNESTING -limits, which will be caught by the parser and result in an error. For more +limits, which will be caught at run time and result in an error. For more about limits see Section~\ref{sub:SystemTap-safety}. \newpage{} \subsection{The stap command} @@ -436,8 +436,10 @@ probe syscall.read = kernel.function("sys_read") { \index{epilogue-style aliases} \index{+=} The statement block that follows an alias definition is implicitly added -as an epilogue to any probe that refers to the alias. The following is an -example: +as an epilogue to any probe that refers to the alias. It is not useful +to define new variable there (since no subsequent code will see it), but +rather the code can take action based upon variables left set by the +prologue or by the user code. The following is an example: \begin{vindent} \begin{verbatim} @@ -445,15 +447,15 @@ example: # epilogue. # probe syscall.read += kernel.function("sys_read") { - fildes = $fd + if (traceme) println ("tracing me") } \end{verbatim} \end{vindent} \subsubsection{Probe alias usage} -Another probe definition may use a previously defined alias. The following -is an example. +A probe alias is used the same way as any built-in probe type, by +naming it: \begin{vindent} \begin{verbatim} @@ -1027,12 +1029,6 @@ type conversions between strings and numbers. Inconsistent type-related use of identifiers signals an error. -\subsubsection{Numbers} -\index{numbers} -Numbers are 64-bit signed integers. The parser will also accept (and wrap -around) values above positive $2^{63}$. - - \subsubsection{Literals} \index{literals} Literals are either strings or integers. Literals can be expressed as decimal, @@ -1041,10 +1037,10 @@ octal, or hexadecimal, using C notation. Type suffixes (e.g., \emph{L} or \subsubsection{Integers\label{sub:Integers}} -\index{integers} +\index{integers} \index{numbers} Integers are decimal, hexadecimal, or octal, and use the same notation as in C. Integers are 64-bit signed quantities, although the parser also accepts -(and wraps around) values above positive $2^{63}$. +(and wraps around) values above positive $2^{63}$ but below $2^{64}$. \subsubsection{Strings\label{sub:Strings}} diff --git a/elaborate.cxx b/elaborate.cxx index abb4c73b..2d9fa7bc 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -2934,11 +2934,11 @@ typeresolution_info::visit_print_format (print_format* e) case print_format::conv_unsigned_uppercase_hex: case print_format::conv_unsigned_lowercase_hex: case print_format::conv_binary: + case print_format::conv_memory: wanted = pe_long; break; case print_format::conv_string: - case print_format::conv_memory: wanted = pe_string; break; } diff --git a/examples/ChangeLog b/examples/ChangeLog index ae011376..78083901 100644 --- a/examples/ChangeLog +++ b/examples/ChangeLog @@ -1,3 +1,8 @@ + +2008-03-09 Wenji Huang <wenji.huang@oracle.com> + + * wait4time.stp: Change reference of $pid to local variable pid. + 2008-03-05 David Smith <dsmith@redhat.com> PR5422 diff --git a/examples/wait4time.stp b/examples/wait4time.stp index bd1628ea..568239b9 100755 --- a/examples/wait4time.stp +++ b/examples/wait4time.stp @@ -47,7 +47,7 @@ probe begin { probe syscall.wait4 { t = gettimeofday_us(); p = pid() entry_wait4[p] = t - wait4_pid[p]=$pid + wait4_pid[p]=pid } probe syscall.wait4.return { diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 497b9d5b..b52ddf7b 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,22 @@ +2008-03-17 Eugene Teo <eteo@redhat.com> + + PR 5947 + * autoconf-tsc-khz.c: Remove "&& defined(__i386__)" to make the test + more pessimistic. + +2008-03-14 Masami Hiramatsu <mhiramat@redhat.com> + + PR 3542 + * autoconf-unregister-kprobes.c : New file. + +2008-03-10 Dave Brolley <brolley@redhat.com> + + PR5189 + * vsprintf.c (_stp_vsnprintf): Arguments for dynamic width and precision + are of type 'int' again. + * loc2c-runtime.h (deref_string): Copy the data only if dst is not NULL. + (deref_buffer): New macro. + 2008-02-27 Martin Hunt <hunt@redhat.com> * sym.h (_stp_module): Add text_size, lock, and unwind data diff --git a/runtime/autoconf-tsc-khz.c b/runtime/autoconf-tsc-khz.c index 6c3f453e..f60bf6d0 100644 --- a/runtime/autoconf-tsc-khz.c +++ b/runtime/autoconf-tsc-khz.c @@ -1,7 +1,7 @@ #include <linux/version.h> #include <asm/tsc.h> -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) && defined(__i386__) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) #error "tsc_khz is not exported" #endif unsigned int *ptsc = &tsc_khz; diff --git a/runtime/autoconf-unregister-kprobes.c b/runtime/autoconf-unregister-kprobes.c new file mode 100644 index 00000000..793891da --- /dev/null +++ b/runtime/autoconf-unregister-kprobes.c @@ -0,0 +1,4 @@ +#include <linux/kprobes.h> + +void * x = (void *)unregister_kprobes; +void * y = (void *)unregister_kretprobes; diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 4674e399..7ea1b1e4 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -623,8 +623,26 @@ for (_len = (maxbytes), _addr = (uintptr_t)(addr); \ _len > 1 && (_c = deref (1, _addr)) != '\0'; \ --_len, ++_addr) \ - *_d++ = _c; \ - *_d = '\0'; \ + if (_d) \ + *_d++ = _c; \ + if (_d) \ + *_d = '\0'; \ + (dst); \ + }) + +#define deref_buffer(dst, addr, numbytes) \ + ({ \ + uintptr_t _addr; \ + size_t _len; \ + unsigned char _c; \ + char *_d = (dst); \ + for (_len = (numbytes), _addr = (uintptr_t)(addr); \ + _len >= 1; \ + --_len, ++_addr) { \ + _c = deref (1, _addr); \ + if (_d) \ + *_d++ = _c; \ + } \ (dst); \ }) diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c index f8283e5c..0bf625a5 100644 --- a/runtime/vsprintf.c +++ b/runtime/vsprintf.c @@ -180,7 +180,7 @@ int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) else if (*fmt == '*') { ++fmt; /* it's the next argument */ - field_width = va_arg(args, int64_t); + field_width = va_arg(args, int); if (field_width < 0) { field_width = -field_width; flags |= STP_LEFT; @@ -196,7 +196,7 @@ int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) else if (*fmt == '*') { ++fmt; /* it's the next argument */ - precision = va_arg(args, int64_t); + precision = va_arg(args, int); } if (precision < 0) precision = 0; @@ -467,11 +467,12 @@ For prologue style alias, the statement block that follows an alias definition is implicitly added as a prologue to any probe that refers to the alias. While for the epilogue style alias, the statement block that follows an alias definition is implicitly added as an epilogue to -any probe that refers to the alias. For example: +any probe that refers to the alias. For example: .SAMPLE probe syscall.read = kernel.function("sys_read") { fildes = $fd + if (execname == "init") next # skip rest of probe } .ESAMPLE defines a new probe point @@ -482,19 +483,23 @@ which expands to .nh .IR kernel.function("sys_read") , .hy -with the given statement as a prologue. And +with the given statement as a prologue, which is useful to predefine +some variables for the alias user and/or to skip probe processing +entirely based on some conditions. And .SAMPLE probe syscall.read += kernel.function("sys_read") { - fildes = $fd + if (tracethis) println ($fd) } .ESAMPLE -defines a new probe point with the given statement as an epilogue. +defines a new probe point with the given statement as an epilogue, which +is useful to take actions based upon variables set or left over by the +the alias user. -Another probe definition -may use the alias like this: +An alias is used just like a built-in probe type. .SAMPLE probe syscall.read { printf("reading fd=%d\n", fildes) + if (fildes > 10) tracethis = 1 } .ESAMPLE diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 85a00b37..9bca845d 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -92,6 +92,60 @@ fault, return instead the err_msg value. user_string_warn:string (addr:long) Copy a string from user space at given address. If the access would fault, signal a warning and return "<unknown>". +.TP +user_string_quoted:string (addr:long) +Copy a string from user space at given address. Any ASCII characters +that are not printable are replaced by the corresponding escape +sequence in the returned string. +.TP +user_string_n:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. If the access +would fault, return "<unknown>". +.TP +user_string_n2:string (addr:long, n:long, err_msg:string) +Copy a string of n bytes from user space at given address. If the access +would fault, return the err_msg value. +.TP +user_string_n_warn:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. If the access +would fault, signal a warning and return "<unknown>". +.TP +user_string_n_quoted:string (addr:long, n:long) +Copy a string of n bytes from user space at given address. Any ASCII +characters that are not printable are replaced by the corresponding escape +sequence in the returned string. If the access would fault, return "<unknown>". +.TP +user_short:long (addr:long) +Copy a short from user space at given address. If the access would fault, +return 0. +.TP +user_short_warn:long (addr:long) +Copy a short from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_int:long (addr:long) +Copy an int from user space at given address. If the access would fault, +return 0. +.TP +user_int_warn:long (addr:long) +Copy an int from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_long:long (addr:long) +Copy a long from user space at given address. If the access would fault, +return 0. +.TP +user_long_warn:long (addr:long) +Copy a long from user space at given address. If the access would fault, +signal a warning and return 0. +.TP +user_char:long (addr:long) +Copy a char from user space at given address. If the access would fault, +return 0. +.TP +user_char_warn:long (addr:long) +Copy a char from user space at given address. If the access would fault, +signal a warning and return 0. .SS STRING .TP strlen:long (str:string) diff --git a/stapprobes.5.in b/stapprobes.5.in index 55fcb3c7..ce8ef52d 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -192,9 +192,10 @@ Here is a list of probe point families currently supported. The variant places a probe near the beginning of the named function, so that parameters are available as context variables. The .B .return -variant places a probe at the moment of return from the named function, so -the return value is available as the "$return" context variable. -The +variant places a probe at the moment +.B after +the return from the named function, so the return value is available +as the "$return" context variable. The .B .inline modifier for .B .function @@ -262,7 +263,7 @@ As an alternative, PATTERN may be a numeric constant, indicating an only, absolute kernel addresses may be specified with the ".absolute" suffix. .PP -Some of the source-level variables, such as function parameters, +Some of the source-level context variables, such as function parameters, locals, globals visible in the compilation unit, may be visible to probe handlers. They may refer to these variables by prefixing their name with "$" within the scripts. In addition, a special syntax @@ -282,6 +283,15 @@ may be repeated to follow more levels of pointers. $var[N] indexes into an array. The index is given with a literal number. +.PP +For ".return" probes, context variables other than the "$return" +value itself are only available for the function call parameters. +The expressions evaluate to the +.IR entry-time +values of those variables, since that is when a snapshot is taken. +Other local variables are not generally accessible, since by the time +a ".return" probe hits, the probed function will have already returned. + .SS USER-SPACE Early prototype support for user-space probing is available in the diff --git a/staptree.cxx b/staptree.cxx index 778691f4..39f5580e 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -930,6 +930,13 @@ void probe::print (ostream& o) const void probe::printsig (ostream& o) const { + const probe_alias *alias = get_alias (); + if (alias) + { + alias->printsig (o); + return; + } + for (unsigned i=0; i<locations.size(); i++) { if (i > 0) o << ","; diff --git a/systemtap.spec.in b/systemtap.spec.in index caaf7e9e..dd105790 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 3 +%define release 1 # Version number of oldest elfutils release that works with systemtap. %define elfutils_version 0.127 diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 32ac6bf2..dae8b452 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,20 @@ +2008-03-21 Eugene Teo <eugeneteo@kernel.sg> + + PR 5528 + * conversions.stp (user_string_n, user_string_n2, user_string_n_warn, + user_string_n_quoted, user_short, user_short_warn, user_int, + user_int_warn, user_long, user_long_warn, user_char, user_char_warn): + New user_* functions. + +2008-03-20 Frank Ch. Eigler <fche@elastic.org> + + PR 5956. + * null.stp: New file, defining global NULL=0. + +2008-03-11 Will Cohen <wcohen@redhat.com> + + * syscalls2.stp (syscall.wait{4|id}): Correct for 2.6.24.n kernels. + 2008-03-06 Ananth N Mavinakayanahalli <ananth@in.ibm.com * i686/syscalls.stp: Handle sys_sigaltstack parameter after diff --git a/tapset/conversions.stp b/tapset/conversions.stp index af993992..70725e9d 100644 --- a/tapset/conversions.stp +++ b/tapset/conversions.stp @@ -1,5 +1,5 @@ // conversions tapset -// Copyright (C) 2005-2007 Red Hat Inc. +// Copyright (C) 2005-2008 Red Hat Inc. // Copyright (C) 2007 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -108,3 +108,131 @@ function user_string_quoted:string (addr:long) %{ /* pure */ _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, MAXSTRINGLEN, 1, 1); %} + +function user_string_n:string (addr:long, n:long) { + return user_string_n2(addr, n, "<unknown>") +} + +function user_string_n2:string (addr:long, n:long, err_msg:string) %{ /* pure */ + long len = THIS->n + 1; + len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; + if (_stp_strncpy_from_user(THIS->__retvalue, + (char __user *) (uintptr_t) THIS->addr, + len) < 0) + strlcpy(THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN); +%} + +function user_string_n_warn:string (addr:long, n:long) %{ /* pure */ + long len = THIS->n + 1; + long rc; + + len = (len > MAXSTRINGLEN) ? MAXSTRINGLEN : len; + rc = _stp_strncpy_from_user(THIS->__retvalue, + (char __user *) (uintptr_t) THIS->addr, len); + if (rc < 0) { + // NB: using error_buffer to get local space for the warning, but we're + // not aborting, so leave last_error alone. + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user string copy fault %ld at %p", rc, + (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + strlcpy (THIS->__retvalue, "<unknown>", MAXSTRINGLEN); + } +%} + +function user_string_n_quoted:string (addr:long, n:long) %{ /* pure */ + long len = THIS->n + 1; + if (THIS->addr == 0) + strlcpy(THIS->__retvalue, "NULL", MAXSTRINGLEN); + else + /* XXX: stp_text_str uses sleepy __get_user() => unsafe ?! */ + _stp_text_str(THIS->__retvalue, (char *)(uintptr_t)THIS->addr, + len, 1, 1); +%} + +// When userspace data is not accessible, the following functions return 0 + +function user_short:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_short_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (short *) (intptr_t) THIS->addr, sizeof(short))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (short *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user short copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_int:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_int_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (int *) (intptr_t) THIS->addr, sizeof(int))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (int *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user int copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_long:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_long_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (long *) (intptr_t) THIS->addr, sizeof(long))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (long *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user long copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + +function user_char:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { +fault: + THIS->__retvalue = 0; + } +%} + +function user_char_warn:long (addr:long) %{ /* pure */ + if (!access_ok(VERIFY_READ, (char *) (intptr_t) THIS->addr, sizeof(char))) + goto fault; + if (__stp_get_user(THIS->__retvalue, (char *) (intptr_t) THIS->addr)) { +fault: + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "user char copy fault %p", (void *) (uintptr_t) THIS->addr); + _stp_warn(CONTEXT->error_buffer); + THIS->__retvalue = 0; + } +%} + diff --git a/tapset/null.stp b/tapset/null.stp new file mode 100644 index 00000000..c8713665 --- /dev/null +++ b/tapset/null.stp @@ -0,0 +1,2 @@ + +global NULL = 0 diff --git a/tapset/syscalls2.stp b/tapset/syscalls2.stp index b0118423..558e89bb 100644 --- a/tapset/syscalls2.stp +++ b/tapset/syscalls2.stp @@ -3023,13 +3023,13 @@ probe syscall.compat_vmsplice.return = kernel.function("compat_sys_vmsplice").re # probe syscall.wait4 = kernel.function("sys_wait4") { name = "wait4" - pid = %( kernel_vr > "2.6.24"%? $upid %: $pid%) + pid = %( kernel_vr >= "2.6.25" %? $upid %: $pid%) status_uaddr = $stat_addr options = $options options_str = _wait4_opt_str($options) rusage_uaddr = $ru argstr = sprintf("%d, %p, %s, %p", - %( kernel_vr > "2.6.24"%? $upid %: $pid%), + %( kernel_vr >= "2.6.25" %? $upid %: $pid%), $stat_addr,_wait4_opt_str($options), $ru) } probe syscall.wait4.return = kernel.function("sys_wait4").return { @@ -3046,7 +3046,7 @@ probe syscall.wait4.return = kernel.function("sys_wait4").return { # probe syscall.waitid = kernel.function("sys_waitid") { name = "waitid" - pid = %( kernel_vr > "2.6.24"%? $upid %: $pid%) + pid = %( kernel_vr >= "2.6.25" %? $upid %: $pid%) which = $which which_str = _waitid_which_str($which) infop_uaddr = $infop @@ -3054,7 +3054,7 @@ probe syscall.waitid = kernel.function("sys_waitid") { options_str = _waitid_opt_str($options) rusage_uaddr = $ru argstr = sprintf("%d, %d, %p, %s, %p", $which, - %( kernel_vr > "2.6.24"%? $upid %: $pid%), $infop, + %( kernel_vr >= "2.6.25" %? $upid %: $pid%), $infop, _waitid_opt_str($options), $ru) } probe syscall.waitid.return = kernel.function("sys_waitid").return { diff --git a/tapsets.cxx b/tapsets.cxx index 147ea3f0..079d87e8 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -201,6 +201,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "goto probe_epilogue;"; o->newline(-1) << "}"; o->newline(); + o->newline() << "c->last_stmt = 0;"; o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = 0;"; @@ -1587,6 +1588,15 @@ struct dwflpp unsigned i = 0; while (i < components.size()) { + /* XXX: This would be desirable, but we don't get the target_symbol token, + and printing that gives us the file:line number too early anyway. */ +#if 0 + // Emit a marker to note which field is being access-attempted, to give + // better error messages if deref() fails. + string piece = string(...target_symbol token...) + string ("#") + stringify(components[i].second); + obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); +#endif + die = dwarf_formref_die (attr_mem, die_mem); const int typetag = dwarf_tag (die); switch (typetag) @@ -2113,6 +2123,7 @@ base_query::base_query(systemtap_session & sess, { bool has_module = get_string_param(params, TOK_MODULE, module_val); assert (has_module); // no other options are possible by construction + (void) has_module; } } @@ -3932,6 +3943,11 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static int enter_kretprobe_probe (struct kretprobe_instance *inst,"; s.op->line() << " struct pt_regs *regs);"; + // Emit an array of kprobe/kretprobe pointers + s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)"; + s.op->newline() << "static void * stap_unreg_kprobes[" << probes_by_module.size() << "];"; + s.op->newline() << "#endif"; + // Emit the actual probe list. // NB: we used to plop a union { struct kprobe; struct kretprobe } into @@ -4102,16 +4118,42 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s) void dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) { + //Unregister kprobes by batch interfaces. + s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)"; + s.op->newline() << "j = 0;"; + s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; + s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];"; + s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];"; + s.op->newline() << "if (! sdp->registered_p) continue;"; + s.op->newline() << "if (!sdp->return_p)"; + s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.kp;"; + s.op->newline(-2) << "}"; + s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes, j);"; + s.op->newline() << "j = 0;"; + s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; + s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];"; + s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];"; + s.op->newline() << "if (! sdp->registered_p) continue;"; + s.op->newline() << "if (sdp->return_p)"; + s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.krp;"; + s.op->newline(-2) << "}"; + s.op->newline() << "unregister_kretprobes((struct kretprobe **)stap_unreg_kprobes, j);"; + s.op->newline() << "#endif"; + s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];"; s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];"; s.op->newline() << "if (! sdp->registered_p) continue;"; s.op->newline() << "if (sdp->return_p) {"; + s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)"; s.op->newline(1) << "unregister_kretprobe (&kp->u.krp);"; + s.op->newline() << "#endif"; s.op->newline() << "atomic_add (kp->u.krp.nmissed, & skipped_count);"; s.op->newline() << "atomic_add (kp->u.krp.kp.nmissed, & skipped_count);"; s.op->newline(-1) << "} else {"; + s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)"; s.op->newline(1) << "unregister_kprobe (&kp->u.kp);"; + s.op->newline() << "#endif"; s.op->newline() << "atomic_add (kp->u.kp.nmissed, & skipped_count);"; s.op->newline(-1) << "}"; s.op->newline() << "sdp->registered_p = 0;"; @@ -4256,7 +4298,9 @@ struct uprobe_builder: public derived_probe_builder int64_t process, address; bool b1 = get_param (parameters, TOK_PROCESS, process); + (void) b1; bool b2 = get_param (parameters, TOK_STATEMENT, address); + (void) b2; bool rr = has_null_param (parameters, TOK_RETURN); assert (b1 && b2); // by pattern_root construction @@ -5751,6 +5795,7 @@ mark_builder::build(systemtap_session & sess, string mark_format_val; bool has_mark_format = get_param (parameters, "format", mark_format_val); assert (has_mark_str); + (void) has_mark_str; if (! cache_initialized) { diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 1596711d..44eb50a7 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,40 @@ +2008-03-27 Frank Ch. Eigler <fche@elastic.org> + + * systemtap.base/cmd_parse.exp: Don't assume $SHELL=bash. + +2008-03-23 Frank Ch. Eigler <fche@elastic.org> + + * lib/stap_run.exp (stap_run): Ignore missing debuginfo warnings. + Try harder to kill stap child in case of timeouts and errors. + +2008-03-23 Frank Ch. Eigler <fche@elastic.org> + + PR 5980. + * lib/systemtap.exp: Set default Snapshot: value from "stap -V" + output. + +2008-03-21 Eugene Teo <eugeneteo@kernel.sg> + + PR 5528 + * systemtap.stress/conversions.stp: Test new user_* functions. + * buildok/conversions.stp: Test new user_* functions. + * buildok/conversions-embedded.stp: Test new user_* functions. + +2008-03-20 Frank Ch. Eigler <fche@elastic.org> + + PR 5956. + * semko/fortyfive.stp: New test. + +2008-03-15 Frank Ch. Eigler <fche@elastic.org> + + * systemtap.base/maxactive.exp, probefunc.exp: Standardize pass msg. + +2008-03-10 Dave Brolley <brolley@redhat.com> + + PR5189 + * systemtap.printf/memory1.{stp,exp}: Rewrite to reflect new %m safety checks. + * systemtap.stress/conversions.exp: Add a test for invalid argument to %m. + 2008-03-05 David Smith <dsmith@redhat.com> PR5422 @@ -30,7 +67,7 @@ 2008-02-23 Frank Ch. Eigler <fche@elastic.org> * systemtap.samples/args.exp: Remove installation-specific paths from - pass/fail judgements. + pass/fail judgements.< 2008-02-23 Frank Ch. Eigler <fche@elastic.org> diff --git a/testsuite/buildok/conversions-embedded.stp b/testsuite/buildok/conversions-embedded.stp index 7aa5a0b4..55f6cdb7 100755 --- a/testsuite/buildok/conversions-embedded.stp +++ b/testsuite/buildok/conversions-embedded.stp @@ -9,5 +9,18 @@ probe begin { print (user_string2 (0, "")) print (user_string_warn (0)) print (user_string_quoted (0)) + + print (user_string_n(0, 5)) + print (user_string_n2(0, 5, "foobar")) + print (user_string_n_warn(0, 0)) + print (user_string_n_quoted(0, 0)) + print (user_short(0)) + print (user_short_warn(0)) + print (user_int(0)) + print (user_int_warn(0)) + print (user_long(0)) + print (user_long_warn(0)) + print (user_char(0)) + print (user_char_warn(0)) } diff --git a/testsuite/buildok/conversions.stp b/testsuite/buildok/conversions.stp index e83bd968..5f151f1d 100755 --- a/testsuite/buildok/conversions.stp +++ b/testsuite/buildok/conversions.stp @@ -12,4 +12,17 @@ probe begin { print (user_string(2342)) print (user_string2(2342,"foobar")) print (user_string_warn(2342)) + + print (user_string_n(2342, 5)) + print (user_string_n2(2342, 5, "foobar")) + print (user_string_n_warn(2342, 5)) + print (user_string_n_quoted(2342, 5)) + print (user_short(2342)) + print (user_short_warn(2342)) + print (user_int(2342)) + print (user_int_warn(2342)) + print (user_long(2342)) + print (user_long_warn(2342)) + print (user_char(2342)) + print (user_char_warn(2342)) } diff --git a/testsuite/configure b/testsuite/configure index 2e29a3d7..bafa86d8 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.1. +# Generated by GNU Autoconf 2.61 for systemtap 0.6.2. # # 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.1' -PACKAGE_STRING='systemtap 0.6.1' +PACKAGE_VERSION='0.6.2' +PACKAGE_STRING='systemtap 0.6.2' 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.1 to adapt to many kinds of systems. +\`configure' configures systemtap 0.6.2 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.1:";; + short | recursive ) echo "Configuration of systemtap 0.6.2:";; 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.1 +systemtap configure 0.6.2 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.1, which was +It was created by systemtap $as_me 0.6.2, 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.1' + VERSION='0.6.2' 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.1, which was +This file was extended by systemtap $as_me 0.6.2, 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.1 +systemtap config.status 0.6.2 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 5eb9b151..8f924936 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.1, systemtap@sources.redhat.com, systemtap) +AC_INIT([systemtap], 0.6.2, systemtap@sources.redhat.com, systemtap) AC_PREREQ(2.59) AC_CONFIG_AUX_DIR(..) diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index c2b4e74d..42efa4f8 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -34,6 +34,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } expect { -timeout 180 -re {^Warning: using '-m' disables cache support.\r\n} {exp_continue} + -re {^WARNING: cannot find module [^\r]*DWARF[^\r]*\r\n} {exp_continue} -re {^Pass\ ([1234]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms\.\r\n} {set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"; exp_continue} -re {^Pass\ ([34]): using cached [^\r]+\r\n} @@ -73,15 +74,22 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } set skipped_probes $expect_out(2,string)} } } - timeout { fail "$TEST_NAME shutdown (timeout)" } + timeout { + fail "$TEST_NAME shutdown (timeout)" + exec kill -INT -[exp_pid] + } eof { fail "$TEST_NAME shutdown (eof)" } } } -re "semantic error:" { fail "$TEST_NAME compilation" } - timeout { fail "$TEST_NAME startup (timeout)" - exec kill -INT [exp_pid] } + timeout { + fail "$TEST_NAME startup (timeout)" + exec kill -INT -[exp_pid] + } eof { fail "$TEST_NAME startup (eof)" } } + # again for good measure + exec kill -INT -[exp_pid] catch close wait } diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index baed0e41..d458e98f 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -58,8 +58,9 @@ proc get_system_info {} { } elseif [file exists $env(SRCDIR)/../SNAPSHOT] { set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT] } else { - set Snapshot "unknown" - } + regexp {version [^)]*} [exec stap -V 2>@ stdout] version + set Snapshot $version + } set Distro "Linux" if [file exists /etc/fedora-release] {set Distro [exec /bin/cat /etc/fedora-release]} if [file exists /etc/redhat-release] {set Distro [exec /bin/cat /etc/redhat-release]} diff --git a/testsuite/semko/fortysix.stp b/testsuite/semko/fortysix.stp new file mode 100755 index 00000000..9774f31f --- /dev/null +++ b/testsuite/semko/fortysix.stp @@ -0,0 +1,3 @@ +#! stap -p2 + +probe begin { if ("foo" == NULL) log ("boo") } # check NULL as integral global diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp index cf15698f..ff347a9d 100644 --- a/testsuite/systemtap.base/cmd_parse.exp +++ b/testsuite/systemtap.base/cmd_parse.exp @@ -56,7 +56,8 @@ expect { wait #stap -c '(((a=42+7)); echo "The answer is $a")' -e 'probe begin {}' -spawn 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 {}} expect { -timeout 60 "The answer is 49" {pass "cmd_parse6"} diff --git a/testsuite/systemtap.base/maxactive.exp b/testsuite/systemtap.base/maxactive.exp index e2175d17..ca95ac53 100644 --- a/testsuite/systemtap.base/maxactive.exp +++ b/testsuite/systemtap.base/maxactive.exp @@ -49,7 +49,7 @@ set skipped2 $skipped_probes # time of the scripts. set test "MAXACTIVE03" if {$skipped1 <= $skipped2} { - pass "$test ($skipped1 skipped probes <= $skipped2 skipped probes)" + pass $test } else { fail "$test ($skipped1 skipped probes > $skipped2 skipped probes)" } diff --git a/testsuite/systemtap.base/probefunc.exp b/testsuite/systemtap.base/probefunc.exp index fbb45534..e5abe22a 100644 --- a/testsuite/systemtap.base/probefunc.exp +++ b/testsuite/systemtap.base/probefunc.exp @@ -42,7 +42,7 @@ set prefix "probefunc:" set output_string "\\mscheduler_tick\\M\r\n" set probepoint "kernel.statement(0x$addr).absolute" set script [format $systemtap_script $probepoint] -stap_run $prefix$probepoint sleep_one_sec $output_string -g -e $script +stap_run "${prefix}.statement.(0xaddr).absolute" sleep_one_sec $output_string -g -e $script # test probefunc() with kernel.function() set probepoint "kernel.function(\"scheduler_tick\")" diff --git a/testsuite/systemtap.printf/memory1.exp b/testsuite/systemtap.printf/memory1.exp index 2389cdc5..7b55a3d7 100644 --- a/testsuite/systemtap.printf/memory1.exp +++ b/testsuite/systemtap.printf/memory1.exp @@ -1,18 +1,4 @@ set test "memory1" -set ::result_string {Memory default width and precision :m: -Memory static precision smaller than input :my st: -Memory dynamic precision smaller than input :my st: -Memory static precision equal to input :my string: -Memory dynamic precision equal to input :my string: -Memory static width default precision : m: -Memory dynamic width default precision : m: -Memory static width smaller than static precision :my string: -Memory static width larger than static precision : my string: -Memory dynamic width smaller than static precision :my string: -Memory dynamic width larger than static precision : my string: -Memory static width smaller than dynamic precision :my string: -Memory static width larger than dynamic precision : my string: -Memory dynamic width smaller than dynamic precision :my string: -Memory dynamic width larger than dynamic precision : my string: +set ::result_string {Test passed } stap_run2 $srcdir/$subdir/$test.stp diff --git a/testsuite/systemtap.printf/memory1.stp b/testsuite/systemtap.printf/memory1.stp index 3b4d6d5e..f9cbf60b 100644 --- a/testsuite/systemtap.printf/memory1.stp +++ b/testsuite/systemtap.printf/memory1.stp @@ -1,27 +1,121 @@ -probe begin { - five = 5; - nine = 9; - fifteen = 15; - s = "my string"; - - printf ("Memory default width and precision\t:%m:\n", s); - - printf ("Memory static precision smaller than input\t:%.5m:\n", s); - printf ("Memory dynamic precision smaller than input\t:%.*m:\n", five, s); - printf ("Memory static precision equal to input\t:%.9m:\n", s); - printf ("Memory dynamic precision equal to input\t:%.*m:\n", nine, s); - - printf ("Memory static width default precision\t:%5m:\n", s); - printf ("Memory dynamic width default precision\t:%*m:\n", five, s); - - printf ("Memory static width smaller than static precision\t:%5.9m:\n", s); - printf ("Memory static width larger than static precision\t:%15.9m:\n", s); - printf ("Memory dynamic width smaller than static precision\t:%*.9m:\n", five, s); - printf ("Memory dynamic width larger than static precision\t:%*.9m:\n", fifteen, s); - printf ("Memory static width smaller than dynamic precision\t:%5.*m:\n", nine, s); - printf ("Memory static width larger than dynamic precision\t:%15.*m:\n", nine, s); - printf ("Memory dynamic width smaller than dynamic precision\t:%*.*m:\n", five, nine, s); - printf ("Memory dynamic width larger than dynamic precision\t:%*.*m:\n", fifteen, nine, s); - - exit() +probe syscall.open { + actualLength = strlen (filename); + + if (actualLength > 5 && actualLength < 15 && filename != "<unknown>") { + four = 4; + five = 5; + fifteen = 15; + success = 1; + + expected_1_1 = sprintf ("%.1s", filename); + testName = "%m default width and precision"; + result = sprintf ("%m", $filename); + if (result != expected_1_1) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_5_5 = sprintf ("%.5s", filename); + testName = "%m static precision smaller than input"; + result = sprintf ("%.5m", $filename); + if (result != expected_5_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic precision smaller than input"; + result = sprintf ("%.*m", five, $filename); + if (result != expected_5_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic precision equal to input"; + expected_actual_actual = filename; + result = sprintf ("%.*m", actualLength, $filename); + if (result != expected_actual_actual) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_5_1 = sprintf (" %.1s", filename); + testName = "%m static width default precision"; + result = sprintf ("%5m", $filename); + if (result != expected_5_1) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic width default precision"; + result = sprintf ("%*m", five, $filename); + if (result != expected_5_1) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_4_5 = expected_5_5; + testName = "%m static width smaller than static precision"; + result = sprintf ("%4.5m", $filename); + if (result != expected_4_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_15_5 = sprintf (" %.5s", filename); + testName = "%m static width larger than static precision"; + result = sprintf ("%15.5m", $filename); + if (result != expected_15_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic width smaller than static precision"; + result = sprintf ("%*.5m", four, $filename); + if (result != expected_4_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic width larger than static precision"; + result = sprintf ("%*.5m", fifteen, $filename); + if (result != expected_15_5) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_4_actual = expected_actual_actual; + testName = "%m static width smaller than dynamic precision"; + result = sprintf ("%4.*m", actualLength, $filename); + if (result != expected_4_actual) { + printf ("Test %s failed\n", testName); + success = 0; + } + + expected_15_actual = sprintf ("%15s", filename); + testName = "%m static width larger than dynamic precision"; + result = sprintf ("%15.*m", actualLength, $filename); + if (result != expected_15_actual) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic width smaller than dynamic precision"; + result = sprintf ("%*.*m", four, actualLength, $filename); + if (result != expected_4_actual) { + printf ("Test %s failed\n", testName); + success = 0; + } + + testName = "%m dynamic width larger than dynamic precision"; + result = sprintf ("%*.*m", fifteen, actualLength, $filename); + if (result != expected_15_actual) { + printf ("Test %s failed\n", testName); + success = 0; + } + + if (success) + print ("Test passed\n"); + + exit(); + } } diff --git a/testsuite/systemtap.stress/conversions.exp b/testsuite/systemtap.stress/conversions.exp index 230904ee..34cd3889 100644 --- a/testsuite/systemtap.stress/conversions.exp +++ b/testsuite/systemtap.stress/conversions.exp @@ -19,6 +19,6 @@ foreach value {0 0xffffffff 0xffffffffffffffff} { } verbose -log "done exp $test $errs" wait - if {$errs == 8} { pass $test } else { fail "$test ($errs)" } + if {$errs == 9} { pass $test } else { fail "$test ($errs)" } verbose -log "done $test $errs" } diff --git a/testsuite/systemtap.stress/conversions.stp b/testsuite/systemtap.stress/conversions.stp index 797626ab..34bd0c28 100644 --- a/testsuite/systemtap.stress/conversions.stp +++ b/testsuite/systemtap.stress/conversions.stp @@ -8,8 +8,21 @@ probe begin { print (kernel_int ($1)) } probe begin { print (kernel_short ($1)) } probe begin { print (kernel_char ($1)) } probe begin { print (kernel_int ($1)) } +probe begin { printf ("%m", $1) } probe begin { print (user_string ($1)) } probe begin { print (user_string2 ($1,"<only suspected, not known>")) } probe begin { print (user_string_warn ($1)) } probe begin { print (user_string_quoted ($1)) } +probe begin { print (user_string_n ($1, 5)) } +probe begin { print (user_string_n2 ($1, 5, "<only suspected, not known>")) } +probe begin { print (user_string_n_warn ($1, 5)) } +probe begin { print (user_string_n_quoted ($1, 5)) } +probe begin { print (user_short ($1)) } +probe begin { print (user_short_warn ($1)) } +probe begin { print (user_int ($1)) } +probe begin { print (user_int_warn ($1)) } +probe begin { print (user_long ($1)) } +probe begin { print (user_long_warn ($1)) } +probe begin { print (user_char ($1)) } +probe begin { print (user_char_warn ($1)) } probe begin(1) { print ("\n") exit () } diff --git a/translate.cxx b/translate.cxx index 855a8e93..f30fca7b 100644 --- a/translate.cxx +++ b/translate.cxx @@ -43,6 +43,7 @@ struct c_unparser: public unparser, public visitor functiondecl* current_function; unsigned tmpvar_counter; unsigned label_counter; + bool probe_or_function_needs_deref_fault_handler; varuse_collecting_visitor vcv_needs_global_locks; @@ -1359,6 +1360,9 @@ c_unparser::emit_function (functiondecl* v) o->newline() << "#define THIS l"; o->newline() << "if (0) goto out;"; // make sure out: is marked used + // set this, in case embedded-c code sets last_error but doesn't otherwise identify itself + o->newline() << "c->last_stmt = " << lex_cast_qstring(*v->tok) << ";"; + // check/increment nesting level o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {"; o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; @@ -1386,6 +1390,7 @@ c_unparser::emit_function (functiondecl* v) } o->newline() << "#define return goto out"; // redirect embedded-C return + this->probe_or_function_needs_deref_fault_handler = false; v->body->visit (this); o->newline() << "#undef return"; @@ -1402,6 +1407,15 @@ c_unparser::emit_function (functiondecl* v) o->newline(1) << "c->last_error = 0;"; o->indent(-1); + if (this->probe_or_function_needs_deref_fault_handler) { + // Emit this handler only if the body included a + // print/printf/etc. using a string or memory buffer! + o->newline(1) << "return;"; + o->newline() << "CATCH_DEREF_FAULT ();"; + o->newline() << "goto out;"; + o->indent(-1); + } + o->newline() << "#undef CONTEXT"; o->newline() << "#undef THIS"; o->newline(-1) << "}\n"; @@ -1486,6 +1500,8 @@ c_unparser::emit_probe (derived_probe* v) } else // This probe is unique. Remember it and output it. { + this->probe_or_function_needs_deref_fault_handler = false; + o->newline(); o->newline() << "#ifdef STP_TIMING"; o->newline() << "static __cacheline_aligned Stat " << "time_" << v->basest()->name << ";"; @@ -1546,6 +1562,14 @@ c_unparser::emit_probe (derived_probe* v) if (v->needs_global_locks ()) emit_unlocks (vut); + if (this->probe_or_function_needs_deref_fault_handler) { + // Emit this handler only if the body included a + // print/printf/etc. using a string or memory buffer! + o->newline() << "return;"; + o->newline() << "CATCH_DEREF_FAULT ();"; + o->newline() << "goto out;"; + } + o->newline(-1) << "}\n"; } @@ -4113,11 +4137,43 @@ c_unparser::visit_print_format (print_format* e) { use_print = 1; tmp[0].override(tmp[0].value() + "\"\\n\""); + components[0].type = print_format::conv_literal; } // Make the [s]printf call, but not if there was an error evaluating the args o->newline() << "if (likely (! c->last_error)) {"; o->indent(1); + + // Generate code to check that any pointer arguments are actually accessible. */ + int arg_ix = 0; + for (unsigned i = 0; i < components.size(); ++i) { + if (components[i].type == print_format::conv_literal) + continue; + + /* Take note of the width and precision arguments, if any. */ + int width_ix = -1, prec_ix= -1; + if (components[i].widthtype == print_format::width_dynamic) + width_ix = arg_ix++; + if (components[i].prectype == print_format::prec_dynamic) + prec_ix = arg_ix++; + + /* Generate a noop call to deref_buffer for %m. */ + if (components[i].type == print_format::conv_memory) { + this->probe_or_function_needs_deref_fault_handler = true; + o->newline() << "deref_buffer (0, " << tmp[arg_ix].value() << ", "; + if (prec_ix == -1) + if (width_ix != -1) + prec_ix = width_ix; + if (prec_ix != -1) + o->line() << tmp[prec_ix].value(); + else + o->line() << "1"; + o->line() << ");"; + } + + ++arg_ix; + } + if (e->print_to_stream) { if (e->print_char) @@ -4151,8 +4207,26 @@ c_unparser::visit_print_format (print_format* e) o->line() << '"' << format_string << '"'; - for (unsigned i = 0; i < tmp.size(); ++i) - o->line() << ", " << tmp[i].value(); + /* Generate the actual arguments. Make sure that they match the expected type of the + format specifier. */ + arg_ix = 0; + for (unsigned i = 0; i < components.size(); ++i) { + if (components[i].type == print_format::conv_literal) + continue; + + /* Cast the width and precision arguments, if any, to 'int'. */ + if (components[i].widthtype == print_format::width_dynamic) + o->line() << ", (int)" << tmp[arg_ix++].value(); + if (components[i].prectype == print_format::prec_dynamic) + o->line() << ", (int)" << tmp[arg_ix++].value(); + + /* The type of the %m argument is 'char*'. */ + if (components[i].type == print_format::conv_memory) + o->line() << ", (char*)(uintptr_t)" << tmp[arg_ix++].value(); + else + o->line() << ", " << tmp[arg_ix++].value(); + } + o->line() << ");"; o->newline(-1) << "}"; o->newline() << res.value() << ";"; |