diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2008-08-06 12:06:06 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2008-08-06 12:06:06 -0400 |
commit | 3c4371661f144c331dd55ee6be8dab57ec2323c8 (patch) | |
tree | 217ccf5864840f14670138b592d90eceacc75fa3 | |
parent | 44ab6f3be72e7b5eeaa2514cea0553b87007ee9c (diff) | |
parent | 0317fad416059781b7a152296c1d8b5a012bf925 (diff) | |
download | systemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.tar.gz systemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.tar.xz systemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.zip |
Merge commit 'origin/master' into pr4225
* commit 'origin/master':
Use relative instead of absolute line. (bug 6611)
move post-0.7 news tidbit to the top
Add test for $$vars, $$params, $$locals.
typographical tweaks for embedded script code
Add $$vars, $$parms, $$locals
Rename $path to $pathname of syscall tapset for 2.6.27
Correct several tests for 2.6.27
c code generation: assert C indentation/nesting cancels out at appropriate points
Tweak test_installcheck for helloworld.meta and traceio2.meta.
Run both tests for installcheck tests.
No need for random suffix file cmdline and sysinfo files in the
Ensure that a systemtap server is available if 'server' is specified
session.h (struct systemtap_session): Added itrace_derived_probe
* syscalls2.stp: Add sys_unlinkat.
Fix on_each_cpu() call for kernels >2.6.26.
Remove unused STAPCONF_MODULE_NSECTIONS
45 files changed, 1737 insertions, 213 deletions
@@ -1,9 +1,88 @@ +2008-08-05 Stan Cox <scox@redhat.com> + + * NEWS: Updated $$vars, $$parms, $$locals. + * tapsets.cxx (visit_target_symbol): Missing break typo. + +2008-08-04 Stan Cox <scox@redhat.com> + + * tapsets.cxx (dwarf_var_expanding_copy_visitor::visit_target_symbol): + Add support for $$vars, $$parms, and $$locals. + * stapprobes.5.in: Likewise. + * doc/langref.tex: Likewise. + 2008-08-02 Frank Ch. Eigler <fche@elastic.org> * translate.h (translator_output::assert_0_indent): New function. * translate.cxx (emit_*): Add a couple of calls to confirm newline(1)/(-1) nest matching. +2008-07-30 Dave Brolley <brolley@redhat.com> + + * stap-client (create_request): No need for random suffix for + cmdline and sysinfo files. + * stap-server (read_data_file): File name is exactly as specified. + Check that it exists. + +2008-07-29 Dave Brolley <brolley@redhat.com> + + * Makefile.am (bin_SCRIPTS): add stap-find-servers, stap-start-server, + stap-find-or-start-server, stap-stop-server. + (EXTRA_DIST): Likewise. + (check): Ensure that a compatible systemtap server is running before + running the tests, if requested. If we start a sterver, stop it after + running the tests. + (installcheck): Likewise. + * stap-client (parse_options): Specify stdin as 'scripts/-' on the + generated command line. + (create_request): Use $script_file instead of '-'. + (unpack_response): Existence of the systemtap temp directory is + optional. + (find_and_connect_to_server): Use stap-find-servers and choose_server. + (choose_server): Rewritten from match_server. Examine multiple + servers. + (connect_to_server): New function. + (maybe_call_staprun): Check for existence of a module. + Use staprun_PATH. + (staprun_PATH): New function. + (fatal): Call disconnect_from_server. + (server_fatal): Likewise. + * stap-server: Catch SIGTERM and SIGINT. + (create_response): Check for the existence of $tmpdir_stap. + (terminate): New function. + * stap-serverd: Catch SIGTERM and SIGINT. + (listen): Run 'nc | stap-server' in the background and wait for them + to finish. + (terminate): Renamed from handle_sigint. Kill avahi-publish-service + and nc. + * systemtap.spec: Add stap-find-servers, stap-start-server, + stap-find-or-start-server, stap-stop-server. + * Makefile.in: Regenerated. + +2008-07-28 Dave Nomura <dcnltc@us.ibm.com> + + * session.h (struct systemtap_session): Added itrace_derived_probe + group. + * elaborate.cxx (systemtap_session::systemtap_session): Added + initialization of itrace_derived_probes. + * tapsets.cxx (struct itrace_derived_probe): Add derived_probe + struct for holding info needed by itrace probes. + (struct itrace_derived_probe_group): New derived_probe_group + to handle itrace probes. + (itrace_derived_probe::itrace_derived_probe): Needed for use with + task_finder. + (itrace_derived_probe_group::join_group): Ditto. + (itrace_derived_probe_group::enroll): Ditto. + (itrace_derived_probe_group::emit_probe_decl): Ditto. + (itrace_derived_probe_group::emit_module_decls): Ditto. + (itrace_derived_probe_group::emit_module_init): Ditto. + (itrace_derived_probe_group::emit_module_exit): Ditto. + * stapprobes.5.in : Added documentation of itrace probe. + +2008-07-24 Josh Stone <joshua.i.stone@intel.com> + + * buildrun.cxx (compile_pass): Remove STAPCONF_MODULE_NSECTIONS, + and add STAPCONF_ONEACHCPU_RETRY + 2008-07-23 Frank Ch. Eigler <fche@elastic.org> From James Bottomley <James.Bottomley@HansenPartnership.com>: diff --git a/Makefile.am b/Makefile.am index 3f619584..eaddfd59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,7 @@ AM_CXXFLAGS = -Wall -Werror dist_man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5 bin_PROGRAMS = stap staprun -bin_SCRIPTS = stap-client stap-server stap-serverd +bin_SCRIPTS = stap-client stap-server stap-serverd stap-find-servers stap-start-server stap-find-or-start-server stap-stop-server stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ @@ -155,7 +155,7 @@ EXTRA_DIST = auto_free.h buildrun.h elaborate.h loc2c.h session.h \ testsuite systemtap.spec runtime tapset \ dwarf_wrappers.h \ git_version.h git_version.sh \ - stap-client stap-server stap-serverd \ + stap-client stap-server stap-serverd stap-find-servers stap-start-server stap-find-or-start-server stap-stop-server \ systemtap.spec EXAMPLE_SOURCE_DIR = $(srcdir)/testsuite/systemtap.examples @@ -250,18 +250,54 @@ SUBDIRS = testsuite doc check: SRCDIR=`cd $(srcdir); pwd`; \ - $(MAKE) -C testsuite check SYSTEMTAP_RUNTIME=$$SRCDIR/runtime SYSTEMTAP_TAPSET=$$SRCDIR/tapset LD_LIBRARY_PATH=$(PWD)/lib-elfutils:$(PWD)/lib-elfutils/systemtap SYSTEMTAP_PATH=$(PWD) RUNTESTFLAGS="$(RUNTESTFLAGS)" + BUILDDIR=`cd $(builddir); pwd`; \ + need_server=0; \ + (echo "X$(EXTRA_TOOL_OPTS)" | grep -q server) && need_server=1; \ + if test $$need_server = 1; then \ + echo "Testing using a systemtap server"; \ + need_server=0; \ + server_pid=`stap-find-or-start-server` || need_server=1; \ + if test $$need_server = 1; then \ + echo "Cannot find or start a systemtap server"; \ + exit -1; \ + fi; \ + client_path="$$BUILDDIR/testsuite/net"; \ + mkdir -p $$BUILDDIR/testsuite/net; \ + cp -p $$SRCDIR/stap-client $$BUILDDIR/testsuite/net/stap; \ + fi; \ + $(MAKE) -C testsuite check SYSTEMTAP_RUNTIME=$$SRCDIR/runtime SYSTEMTAP_TAPSET=$$SRCDIR/tapset LD_LIBRARY_PATH=$(PWD)/lib-elfutils:$(PWD)/lib-elfutils/systemtap SYSTEMTAP_PATH="$$client_path:$(PWD)" RUNTESTFLAGS="$(RUNTESTFLAGS)"; \ + if test "X$$server_pid" != "X"; then \ + stap-stop-server $$server_pid; \ + fi installcheck: + BUILDDIR=`cd $(builddir); pwd`; \ if test \! -e $(DESTDIR)$(bindir)/stap; then \ echo $(DESTDIR)$(bindir)/stap doesn\'t exist, run make install; \ exit -1; \ - fi + fi; \ if test $(builddir)/stap -nt $(DESTDIR)$(bindir)/stap; then \ echo "$(DESTDIR)$(bindir)/stap is not recent, run make install"; \ exit -1; \ + fi; \ + need_server=0; \ + (echo "X$(EXTRA_TOOL_OPTS)" | grep -q server) && need_server=1; \ + if test $$need_server = 1; then \ + echo "Testing using a systemtap server"; \ + need_server=0; \ + server_pid=`stap-find-or-start-server` || need_server=1; \ + if test $$need_server = 1; then \ + echo "Cannot find or start a systemtap server"; \ + exit -1; \ + fi; \ + client_path=":$$BUILDDIR/testsuite/net"; \ + mkdir -p $$BUILDDIR/testsuite/net; \ + cp -p $(DESTDIR)$(bindir)/stap-client $$BUILDDIR/testsuite/net/stap; \ + fi; \ + $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" EXTRA_SYSTEMTAP_PATH="$(EXTRA_SYSTEMTAP_PATH)$$client_path"; \ + if test "X$$server_pid" != "X"; then \ + stap-stop-server $$server_pid; \ fi - $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" rpm: systemtap.spec dist rpmbuild --define "_sourcedir $(PWD)/" -ba systemtap.spec diff --git a/Makefile.in b/Makefile.in index cc8d4fd3..e3b6f146 100644 --- a/Makefile.in +++ b/Makefile.in @@ -275,7 +275,7 @@ AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR= AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wunused -Wformat=2 -W AM_CXXFLAGS = -Wall -Werror dist_man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5 -bin_SCRIPTS = stap-client stap-server stap-serverd +bin_SCRIPTS = stap-client stap-server stap-serverd stap-find-servers stap-start-server stap-find-or-start-server stap-stop-server stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ @@ -334,7 +334,7 @@ EXTRA_DIST = auto_free.h buildrun.h elaborate.h loc2c.h session.h \ testsuite systemtap.spec runtime tapset \ dwarf_wrappers.h \ git_version.h git_version.sh \ - stap-client stap-server stap-serverd \ + stap-client stap-server stap-serverd stap-find-servers stap-start-server stap-find-or-start-server stap-stop-server \ systemtap.spec EXAMPLE_SOURCE_DIR = $(srcdir)/testsuite/systemtap.examples @@ -1636,18 +1636,54 @@ uninstall-local: check: SRCDIR=`cd $(srcdir); pwd`; \ - $(MAKE) -C testsuite check SYSTEMTAP_RUNTIME=$$SRCDIR/runtime SYSTEMTAP_TAPSET=$$SRCDIR/tapset LD_LIBRARY_PATH=$(PWD)/lib-elfutils:$(PWD)/lib-elfutils/systemtap SYSTEMTAP_PATH=$(PWD) RUNTESTFLAGS="$(RUNTESTFLAGS)" + BUILDDIR=`cd $(builddir); pwd`; \ + need_server=0; \ + (echo "X$(EXTRA_TOOL_OPTS)" | grep -q server) && need_server=1; \ + if test $$need_server = 1; then \ + echo "Testing using a systemtap server"; \ + need_server=0; \ + server_pid=`stap-find-or-start-server` || need_server=1; \ + if test $$need_server = 1; then \ + echo "Cannot find or start a systemtap server"; \ + exit -1; \ + fi; \ + client_path="$$BUILDDIR/testsuite/net"; \ + mkdir -p $$BUILDDIR/testsuite/net; \ + cp -p $$SRCDIR/stap-client $$BUILDDIR/testsuite/net/stap; \ + fi; \ + $(MAKE) -C testsuite check SYSTEMTAP_RUNTIME=$$SRCDIR/runtime SYSTEMTAP_TAPSET=$$SRCDIR/tapset LD_LIBRARY_PATH=$(PWD)/lib-elfutils:$(PWD)/lib-elfutils/systemtap SYSTEMTAP_PATH="$$client_path:$(PWD)" RUNTESTFLAGS="$(RUNTESTFLAGS)"; \ + if test "X$$server_pid" != "X"; then \ + stap-stop-server $$server_pid; \ + fi installcheck: + BUILDDIR=`cd $(builddir); pwd`; \ if test \! -e $(DESTDIR)$(bindir)/stap; then \ echo $(DESTDIR)$(bindir)/stap doesn\'t exist, run make install; \ exit -1; \ - fi + fi; \ if test $(builddir)/stap -nt $(DESTDIR)$(bindir)/stap; then \ echo "$(DESTDIR)$(bindir)/stap is not recent, run make install"; \ exit -1; \ + fi; \ + need_server=0; \ + (echo "X$(EXTRA_TOOL_OPTS)" | grep -q server) && need_server=1; \ + if test $$need_server = 1; then \ + echo "Testing using a systemtap server"; \ + need_server=0; \ + server_pid=`stap-find-or-start-server` || need_server=1; \ + if test $$need_server = 1; then \ + echo "Cannot find or start a systemtap server"; \ + exit -1; \ + fi; \ + client_path=":$$BUILDDIR/testsuite/net"; \ + mkdir -p $$BUILDDIR/testsuite/net; \ + cp -p $(DESTDIR)$(bindir)/stap-client $$BUILDDIR/testsuite/net/stap; \ + fi; \ + $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" EXTRA_SYSTEMTAP_PATH="$(EXTRA_SYSTEMTAP_PATH)$$client_path"; \ + if test "X$$server_pid" != "X"; then \ + stap-stop-server $$server_pid; \ fi - $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" rpm: systemtap.spec dist rpmbuild --define "_sourcedir $(PWD)/" -ba systemtap.spec @@ -1,5 +1,8 @@ * What's new +- A formatted string representation of the variables, parameters, or local + variables at a probe point is now supported via the special $$vars, + $$parms, and $$locals context variables. * What's new in version 0.7 diff --git a/buildrun.cxx b/buildrun.cxx index 72c0d1c7..c2ebdce5 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -95,9 +95,9 @@ 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; - o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-module-nsections.c, -DSTAPCONF_MODULE_NSECTIONS,)" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-real-parent.c, -DSTAPCONF_REAL_PARENT,)" << endl; o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-uaccess.c, -DSTAPCONF_LINUX_UACCESS_H,)" << endl; + o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-oneachcpu-retry.c, -DSTAPCONF_ONEACHCPU_RETRY,)" << endl; #if 0 /* NB: For now, the performance hit of probe_kernel_read/write (vs. our * homegrown safe-access functions) is deemed undesireable, so we'll skip diff --git a/doc/langref.tex b/doc/langref.tex index e2c630d4..413ece4d 100644 --- a/doc/langref.tex +++ b/doc/langref.tex @@ -771,7 +771,7 @@ pointers, and arrays. \texttt{\$var} refers to an in-scope variable var. If it is a type similar to an integer, it will be cast to a 64-bit integer for script use. Pointers similar to a string (char {*}) are copied to SystemTap string values by the -kernel\_string() or user\_string functions(). +\texttt{kernel\_string()} or \texttt{user\_string()} functions. \texttt{\$var->field} traverses a structure's field. The indirection operator may be repeated to follow additional levels of pointers. @@ -779,6 +779,17 @@ may be repeated to follow additional levels of pointers. \texttt{\$var{[}N]} indexes into an array. The index is given with a literal number. +\texttt{\$\$vars} expands to a character string that is equivalent to +\texttt{sprintf("parm1=\%x ... parmN=\%x var1=\%x ... varN=\%x", \$parm1, ..., \$parmN, +\$var1, ..., \$varN)} + +\texttt{\$\$locals} expands to a character string that is equivalent to +\texttt{sprintf("var1=\%x ... varN=\%x", \$var1, ..., \$varN)} + +\texttt{\$\$parms} expands to a character string that is equivalent to +\texttt{sprintf("parm1=\%x ... parmN=\%x", \$parm1, ..., \$parmN)} + + \subsubsection{kernel.function, module().function} \index{kernel.function} \index{module().function} diff --git a/elaborate.cxx b/elaborate.cxx index 73358a1d..0950b086 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1187,6 +1187,7 @@ systemtap_session::systemtap_session (): dwarf_derived_probes(0), uprobe_derived_probes(0), utrace_derived_probes(0), + itrace_derived_probes(0), task_finder_derived_probes(0), timer_derived_probes(0), profile_derived_probes(0), diff --git a/runtime/ChangeLog b/runtime/ChangeLog index f12b5d9a..a8d73ffd 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,8 @@ +2008-07-24 Josh Stone <joshua.i.stone@intel.com> + + * runtime/autoconf-module-nsections.c: removed + * runtime/autoconf-oneachcpu-retry.c: added + 2008-07-21 David Smith <dsmith@redhat.com> * task_finder_vma.c (__stp_tf_vma_initialize): New function to diff --git a/runtime/autoconf-module-nsections.c b/runtime/autoconf-module-nsections.c deleted file mode 100644 index c1ce58b7..00000000 --- a/runtime/autoconf-module-nsections.c +++ /dev/null @@ -1,8 +0,0 @@ -#include <linux/module.h> - -struct module_sect_attrs x; - -void foo (void) -{ - (void) x.nsections; -} diff --git a/runtime/autoconf-oneachcpu-retry.c b/runtime/autoconf-oneachcpu-retry.c new file mode 100644 index 00000000..304d9842 --- /dev/null +++ b/runtime/autoconf-oneachcpu-retry.c @@ -0,0 +1,7 @@ +#include <linux/smp.h> + +void ____autoconf_func(void) +{ + /* Older on_each_cpu() calls had a "retry" parameter */ + (void)on_each_cpu(NULL, NULL, 0, 0); +} diff --git a/runtime/itrace.c b/runtime/itrace.c new file mode 100644 index 00000000..3ee48265 --- /dev/null +++ b/runtime/itrace.c @@ -0,0 +1,438 @@ +/* + * user space instruction tracing + * Copyright (C) 2005, 2006, 2007, 2008 IBM Corp. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/rcupdate.h> +#include <linux/utrace.h> +#include <asm/string.h> +#include <asm/tracehook.h> +#include <asm/ptrace.h> +#include "uprobes/uprobes.h" + +#ifndef put_task_struct +#define put_task_struct(t) \ + BUG_ON(atomic_dec_and_test(&tsk->usage)) +#endif + +#ifdef CONFIG_PPC +struct bpt_info { + unsigned long addr; + unsigned int instr; +}; + +struct atomic_ss_info { + int step_over_atomic; + struct bpt_info end_bpt; + struct bpt_info br_bpt; +}; + +static int handle_ppc_atomic_seq(struct task_struct *tsk, struct pt_regs *regs, + struct atomic_ss_info *ss_info); +static void remove_atomic_ss_breakpoint (struct task_struct *tsk, + struct bpt_info *bpt); +#endif + +struct itrace_info { + pid_t tid; + u32 step_flag; + struct stap_itrace_probe *itrace_probe; +#ifdef CONFIG_PPC + struct atomic_ss_info ppc_atomic_ss; +#endif + struct task_struct *tsk; + struct utrace_attached_engine *engine; + struct list_head link; +}; + +static u32 debug = 1; + +static LIST_HEAD(usr_itrace_info); +static spinlock_t itrace_lock; +static struct itrace_info *create_itrace_info( + struct task_struct *tsk, u32 step_flag, + struct stap_itrace_probe *itrace_probe); + +static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs, + u32 action, siginfo_t *info, + const struct k_sigaction *orig_ka, + struct k_sigaction *return_ka) +{ + struct itrace_info *ui; + u32 return_flags; + unsigned long data = 0; +#ifdef CONFIG_PPC + data = mfspr(SPRN_SDAR); +#endif + + ui = rcu_dereference(engine->data); + WARN_ON(!ui); + + if (info->si_signo != SIGTRAP || !ui) + return UTRACE_ACTION_RESUME; + + /* normal case: continue stepping, hide this trap from other engines */ + return_flags = ui->step_flag | UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN | + UTRACE_ACTION_NEWSTATE; + +#ifdef CONFIG_PPC + if (ui->ppc_atomic_ss.step_over_atomic) { + remove_atomic_ss_breakpoint(tsk, &ui->ppc_atomic_ss.end_bpt); + if (ui->ppc_atomic_ss.br_bpt.addr) + remove_atomic_ss_breakpoint(tsk, + &ui->ppc_atomic_ss.br_bpt); + ui->ppc_atomic_ss.step_over_atomic = 0; + } + + if (handle_ppc_atomic_seq(tsk, regs, &ui->ppc_atomic_ss)) + return_flags = UTRACE_ACTION_RESUME | UTRACE_ACTION_NEWSTATE | + UTRACE_SIGNAL_IGN; +#endif + + enter_itrace_probe(ui->itrace_probe, regs, (void *)&data); + + return return_flags; +} + +static u32 usr_itrace_report_clone(struct utrace_attached_engine *engine, + struct task_struct *parent, unsigned long clone_flags, + struct task_struct *child) +{ + return UTRACE_ACTION_RESUME; +} + +static u32 usr_itrace_report_death(struct utrace_attached_engine *e, + struct task_struct *tsk) +{ + struct itrace_info *ui = rcu_dereference(e->data); + WARN_ON(!ui); + + return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_DETACH); +} + +static const struct utrace_engine_ops utrace_ops = +{ + .report_signal = usr_itrace_report_signal, + .report_clone = usr_itrace_report_clone, + .report_death = usr_itrace_report_death +}; + + +static struct itrace_info *create_itrace_info( + struct task_struct *tsk, u32 step_flag, + struct stap_itrace_probe *itrace_probe) +{ + struct itrace_info *ui; + + if (debug) + printk(KERN_INFO "create_itrace_info: tid=%d\n", tsk->pid); + /* initialize ui */ + ui = kzalloc(sizeof(struct itrace_info), GFP_USER); + ui->tsk = tsk; + ui->tid = tsk->pid; + ui->step_flag = step_flag; + ui->itrace_probe = itrace_probe; +#ifdef CONFIG_PPC + ui->ppc_atomic_ss.step_over_atomic = 0; +#endif + INIT_LIST_HEAD(&ui->link); + + /* push ui onto usr_itrace_info */ + spin_lock(&itrace_lock); + list_add(&ui->link, &usr_itrace_info); + + /* attach a single stepping engine */ + ui->engine = utrace_attach(ui->tsk, UTRACE_ATTACH_CREATE, &utrace_ops, ui); + if (IS_ERR(ui->engine)) { + printk(KERN_ERR "utrace_attach returns %ld\n", + PTR_ERR(ui->engine)); + ui = NULL; + } else { + utrace_set_flags(tsk, ui->engine, ui->engine->flags | + ui->step_flag | + UTRACE_EVENT(CLONE) | UTRACE_EVENT_SIGNAL_ALL | + UTRACE_EVENT(DEATH)); + } + spin_unlock(&itrace_lock); + return ui; +} + +static struct itrace_info *find_itrace_info(pid_t tid) +{ + struct itrace_info *ui = NULL; + + spin_lock(&itrace_lock); + list_for_each_entry(ui, &usr_itrace_info, link) { + if (ui->tid == tid) + goto done; + } + ui = NULL; +done: + spin_unlock(&itrace_lock); + return ui; +} + + +int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe *p) +{ + struct itrace_info *ui; + struct task_struct *tsk; + + rcu_read_lock(); + tsk = find_task_by_pid(tid); + if (!tsk) { + printk(KERN_ERR "usr_itrace_init: Cannot find process %d\n", tid); + rcu_read_unlock(); + return 1; + } + + get_task_struct(tsk); + ui = create_itrace_info(tsk, + (single_step ? + UTRACE_ACTION_SINGLESTEP : UTRACE_ACTION_BLOCKSTEP), p); + if (!ui) + return 1; + + put_task_struct(tsk); + rcu_read_unlock(); + + spin_lock_init(&itrace_lock); + + /* set initial state */ + spin_lock(&itrace_lock); + spin_unlock(&itrace_lock); + printk(KERN_INFO "usr_itrace_init: completed for tid = %d\n", tid); + + return 0; +} + +void static remove_usr_itrace_info(struct itrace_info *ui) +{ + struct itrace_info *tmp; + + if (!ui) + return; + + if (debug) + printk(KERN_INFO "remove_usr_itrace_info: tid=%d\n", ui->tid); + + spin_lock(&itrace_lock); + if (ui->tsk && ui->engine) { + (void) utrace_detach(ui->tsk, ui->engine); + } + list_del(&ui->link); + spin_unlock(&itrace_lock); + kfree(ui); +} + +void static cleanup_usr_itrace(void) +{ + struct itrace_info *tmp; + struct itrace_info *ui; + + if (debug) + printk(KERN_INFO "cleanup_usr_itrace called\n"); + + list_for_each_entry_safe(ui, tmp, &usr_itrace_info, link) { + remove_usr_itrace_info(ui); + } +} + + +#ifdef CONFIG_PPC +#define PPC_INSTR_SIZE 4 +#define TEXT_SEGMENT_BASE 1 + +/* Instruction masks used during single-stepping of atomic sequences. */ +#define LWARX_MASK 0xfc0007fe +#define LWARX_INSTR 0x7c000028 +#define LDARX_INSTR 0x7c0000A8 +#define STWCX_MASK 0xfc0007ff +#define STWCX_INSTR 0x7c00012d +#define STDCX_INSTR 0x7c0001ad +#define BC_MASK 0xfc000000 +#define BC_INSTR 0x40000000 +#define ATOMIC_SEQ_LENGTH 16 +#define BPT_TRAP 0x7fe00008 +#define INSTR_SZ sizeof(int) + +static int get_instr(unsigned long addr, char *msg) +{ + unsigned int instr; + + if (copy_from_user(&instr, (const void __user *) addr, + sizeof(instr))) { + printk(KERN_ERR "get_instr failed: %s\n", msg); + WARN_ON(1); + } + return instr; + +} + +static void insert_atomic_ss_breakpoint (struct task_struct *tsk, + struct bpt_info *bpt) +{ + unsigned int bp_instr = BPT_TRAP; + unsigned int cur_instr; + + cur_instr = get_instr(bpt->addr, "insert_atomic_ss_breakpoint"); + if (cur_instr != BPT_TRAP) { + bpt->instr = cur_instr; + WARN_ON(access_process_vm(tsk, bpt->addr, &bp_instr, INSTR_SZ, 1) != + INSTR_SZ); + } +} + +static void remove_atomic_ss_breakpoint (struct task_struct *tsk, + struct bpt_info *bpt) +{ + WARN_ON(access_process_vm(tsk, bpt->addr, &bpt->instr, INSTR_SZ, 1) != + INSTR_SZ); +} + +/* locate the branch destination. Return -1 if not a branch. */ +static unsigned long +branch_dest (int opcode, int instr, struct pt_regs *regs, unsigned long pc) +{ + unsigned long dest; + int immediate; + int absolute; + int ext_op; + + absolute = (int) ((instr >> 1) & 1); + + switch (opcode) { + case 18: + immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */ + if (absolute) + dest = immediate; + else + dest = pc + immediate; + break; + + case 16: + immediate = ((instr & ~3) << 16) >> 16; /* br conditional */ + if (absolute) + dest = immediate; + else + dest = pc + immediate; + break; + + case 19: + ext_op = (instr >> 1) & 0x3ff; + + if (ext_op == 16) { + /* br conditional register */ + dest = regs->link & ~3; + /* FIX: we might be in a signal handler */ + WARN_ON(dest > 0); + } else if (ext_op == 528) { + /* br cond to ctr reg */ + dest = regs->ctr & ~3; + + /* for system call dest < TEXT_SEGMENT_BASE */ + if (dest < TEXT_SEGMENT_BASE) + dest = regs->link & ~3; + } else + return -1; + break; + + default: + return -1; + } + return dest; +} + +/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX + instruction and ending with a STWCX/STDCX instruction. If such a sequence + is found, attempt to step through it. A breakpoint is placed at the end of + the sequence. */ + +static int handle_ppc_atomic_seq(struct task_struct *tsk, struct pt_regs *regs, + struct atomic_ss_info *ss_info) +{ + unsigned long ip = regs->nip; + unsigned long start_addr; + unsigned int instr; + int got_stx = 0; + int i; + int ret; + + unsigned long br_dest; /* bpt at branch instr's destination */ + int bc_instr_count = 0; /* conditional branch instr count */ + + instr = get_instr(regs->nip, "handle_ppc_atomic_seq:1"); + /* Beginning of atomic sequence starts with lwarx/ldarx instr */ + if ((instr & LWARX_MASK) != LWARX_INSTR + && (instr & LWARX_MASK) != LDARX_INSTR) + return 0; + + start_addr = regs->nip; + for (i = 0; i < ATOMIC_SEQ_LENGTH; ++i) { + ip += INSTR_SZ; + instr = get_instr(ip, "handle_ppc_atomic_seq:2"); + + /* look for at most one conditional branch in the sequence + * and put a bpt at it's destination address + */ + if ((instr & BC_MASK) == BC_INSTR) { + if (bc_instr_count >= 1) + return 0; /* only handle a single branch */ + + br_dest = branch_dest (BC_INSTR >> 26, instr, regs, ip); + + if (br_dest != -1 && + br_dest >= TEXT_SEGMENT_BASE) { + ss_info->br_bpt.addr = br_dest; + bc_instr_count++; + } + } + + if ((instr & STWCX_MASK) == STWCX_INSTR + || (instr & STWCX_MASK) == STDCX_INSTR) { + got_stx = 1; + break; + } + } + + /* Atomic sequence ends with a stwcx/stdcx instr */ + if (!got_stx) + return 0; + + ip += INSTR_SZ; + instr = get_instr(ip, "handle_ppc_atomic_seq:3"); + if ((instr & BC_MASK) == BC_INSTR) { + ip += INSTR_SZ; + instr = get_instr(ip, "handle_ppc_atomic_seq:4"); + } + + /* Insert a breakpoint right after the end of the atomic sequence. */ + ss_info->end_bpt.addr = ip; + + /* Check for duplicate bpts */ + if (bc_instr_count && (ss_info->br_bpt.addr >= start_addr && + ss_info->br_bpt.addr <= ss_info->end_bpt.addr)) + ss_info->br_bpt.addr = 0; + + insert_atomic_ss_breakpoint (tsk, &ss_info->end_bpt); + if (ss_info->br_bpt.addr) + insert_atomic_ss_breakpoint (tsk, &ss_info->br_bpt); + + ss_info->step_over_atomic = 1; + return 1; +} +#endif diff --git a/runtime/time.c b/runtime/time.c index 8a0b6fad..6b01cebe 100644 --- a/runtime/time.c +++ b/runtime/time.c @@ -237,7 +237,11 @@ _stp_init_time(void) return -1; stp_timer_reregister = 1; +#ifdef STAPCONF_ONEACHCPU_RETRY ret = on_each_cpu(__stp_init_time, NULL, 0, 1); +#else + ret = on_each_cpu(__stp_init_time, NULL, 1); +#endif #ifdef CONFIG_CPU_FREQ if (!ret && !__stp_constant_freq()) { @@ -32,6 +32,7 @@ struct be_derived_probe_group; struct dwarf_derived_probe_group; struct uprobe_derived_probe_group; struct utrace_derived_probe_group; +struct itrace_derived_probe_group; struct task_finder_derived_probe_group; struct timer_derived_probe_group; struct profile_derived_probe_group; @@ -146,6 +147,7 @@ struct systemtap_session dwarf_derived_probe_group* dwarf_derived_probes; uprobe_derived_probe_group* uprobe_derived_probes; utrace_derived_probe_group* utrace_derived_probes; + itrace_derived_probe_group* itrace_derived_probes; task_finder_derived_probe_group* task_finder_derived_probes; timer_derived_probe_group* timer_derived_probes; profile_derived_probe_group* profile_derived_probes; diff --git a/stap-client b/stap-client index 8c3607ae..d6bb8442 100755 --- a/stap-client +++ b/stap-client @@ -169,8 +169,13 @@ function parse_options { # If the script file was given and it's not '-', then replace it with its # client-temp-name in the command string. - if test "X$script_file" != "X" -a "$script_file" != "-"; then - local local_name=`generate_client_temp_name $script_file` + if test "X$script_file" != "X"; then + local local_name + if test "$script_file" != "-"; then + local_name=`generate_client_temp_name $script_file` + else + local_name=$script_file + fi cmdline=`echo $cmdline | sed s,$script_file,script/$local_name,` fi } @@ -257,7 +262,7 @@ function process_R { # Include the given file or directory in the client's temporary # tree to be sent to the server. function include_file_or_directory { - # Add a symbolic link of the named directory to our temporary directory + # Add a symbolic link of the named file or directory to our temporary directory local local_name=`generate_client_temp_name $2` mkdir -p $tmpdir_client/$1/`dirname $local_name` || \ fatal "ERROR: could not create $tmpdir_client/$1/`dirname $local_name`" @@ -291,22 +296,16 @@ function create_request { if test "X$script_file" != "X"; then if test "$script_file" = "-"; then mkdir -p $tmpdir_client/script || \ - fatal "ERROR: cannot create temporary diectory " $tmpdir_client/script - cat > $tmpdir_client/script/- + fatal "ERROR: cannot create temporary directory " $tmpdir_client/script + cat > $tmpdir_client/script/$script_file else include_file_or_directory script $script_file > /dev/null fi fi - # Add the necessary info to special files in our temporary directory. Do this - # after linking in -I and -R directories in order to guarantee no name clashes. - tmpfile=`mktemp cmdline.XXXXXX` || \ - fatal "ERROR: cannot create temporary file " - echo "cmdline: $cmdline" > $tmpfile - - tmpfile=`mktemp sysinfo.XXXXXX` || \ - fatal "ERROR: cannot create temporary file " $tmpfile - echo "sysinfo: `client_sysinfo`" > $tmpfile + # Add the necessary info to special files in our temporary directory. + echo "cmdline: $cmdline" > cmdline + echo "sysinfo: `client_sysinfo`" > sysinfo } # function client_sysinfo @@ -343,9 +342,6 @@ function package_request { # client -> "request:" # server -> "ready:" # client -> $tar_client -# -# $tmpdir_client is provided on the request so that the server knows what -# the tar file will expand to. function send_request { echo "request:" >&3 # Get the server's response. @@ -404,7 +400,7 @@ function unpack_response { tar -xzf $tar_server || \ fatal "ERROR: Unpacking of server response, $tar_server, failed" - # Identify the server's request tree. The tar file should have expanded + # Identify the server's response tree. The tar file should have expanded # into a single directory named to match $tmpdir_prefix_server.?????? # which should now be the only item in the current directory. test "`ls | wc -l`" = 1 || \ @@ -419,34 +415,39 @@ function unpack_response { # Check the contents of the expanded directory. It should contain: # 1) a file called stdout # 2) a file called stderr - # 3) a directory named to match stap?????? - test "`ls $tmpdir_server | wc -l`" = 3 || \ - fatal "ERROR: Wrong number of files after expansion of server's tar file" + # 3) optionally a directory named to match stap?????? + local num_files=`ls $tmpdir_server | wc -l` + test $num_files = 3 -o $num_files = 2 || \ + fatal "ERROR: Wrong number of files in server's temp directory" test -f $tmpdir_server/stdout || \ fatal "ERROR: `pwd`/$tmpdir_server/stdout does not exist or is not a regular file" test -f $tmpdir_server/stderr || \ fatal "ERROR: `pwd`/$tmpdir_server/stderr does not exist or is not a regular file" + # See if there is a systemtap temp directory tmpdir_stap=`ls $tmpdir_server | grep stap` tmpdir_stap=`expr "$tmpdir_stap" : "\\\(stap......\\\)"` - test "X$tmpdir_stap" = "X" && \ - fatal "ERROR: `pwd`/$tmpdir_server/stap?????? does not exist" - test -d $tmpdir_server/$tmpdir_stap || \ - fatal "ERROR: `pwd`/$tmpdir_server/$tmpdir_stap is not a directory" - - # Move the systemtap temp directory to a local temp location, if -k - # was specified. - if test $keep_temps = 1; then - local local_tmpdir_stap=`mktemp -dt stapXXXXXX` || \ - fatal "ERROR: cannot create temporary directory " $local_tmpdir_stap - mv $tmpdir_server/$tmpdir_stap/* $local_tmpdir_stap 2>/dev/null - rm -fr $tmpdir_server/$tmpdir_stap - - # Correct the name of the temp directory in the server's stderr output - sed -i "s,^Keeping temporary directory.*,Keeping temporary directory \"$local_tmpdir_stap\"," $tmpdir_server/stderr - tmpdir_stap=$local_tmpdir_stap - else - tmpdir_stap=`pwd`/$tmpdir_stap + if test "X$tmpdir_stap" != "X"; then + test -d $tmpdir_server/$tmpdir_stap || \ + fatal "ERROR: `pwd`/$tmpdir_server/$tmpdir_stap is not a directory" + + # Move the systemtap temp directory to a local temp location, if -k + # was specified. + if test $keep_temps = 1; then + local local_tmpdir_stap=`mktemp -dt stapXXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $local_tmpdir_stap + mv $tmpdir_server/$tmpdir_stap/* $local_tmpdir_stap 2>/dev/null + rm -fr $tmpdir_server/$tmpdir_stap + + # Correct the name of the temp directory in the server's stderr output + sed -i "s,^Keeping temporary directory.*,Keeping temporary directory \"$local_tmpdir_stap\"," $tmpdir_server/stderr + tmpdir_stap=$local_tmpdir_stap + else + tmpdir_stap=`pwd`/$tmpdir_stap + fi + + # Make sure we own the systemtap temp directory if we are root. + test $EUID = 0 && chown $EUID:$EUID $tmpdir_stap fi # Move the contents of the server's tmpdir down one level to the @@ -454,95 +455,57 @@ function unpack_response { mv $tmpdir_server/* . 2>/dev/null rm -fr $tmpdir_server tmpdir_server=`pwd` - - # Make sure we own the systemtap temp directory if we are root. - test $EUID = 0 && chown $EUID:$EUID $tmpdir_stap } # function: find_and_connect_to_server # -# Find and establish connection with a compatibale stap server. +# Find and establish connection with a compatible stap server. function find_and_connect_to_server { - # Find a server - server=`avahi-browse $avahi_service_tag --terminate -r 2>/dev/null | match_server` - port=`expr "$server" : '[^/]*/\(.*\)'` - server=`expr "$server" : '\([^/]*\)/.*'` - - test "X$server" != "X" || \ - fatal "ERROR: cannot find a server" - - test "X$port" != "X" || \ - fatal "ERROR: server port not provided" - - # Open a connection to the server - if ! exec 3<> /dev/tcp/$server/$port; then - fatal "ERROR: cannot connect to server at /dev/tcp/$server/$port" - fi + # Use a temp file here instead of a pipeline so that the side effects + # of choose_server are seen by the rest of this script. + cd $tmpdir_client + stap-find-servers > servers + choose_server < servers + rm -fr servers } -# function: match_server +# function: choose_server # -# Find a suitable server using the avahi-browse output provided on stdin. -function match_server { - local server_ip - - # Loop over the avahi service descriptors. - while read +# Examine each line from stdin and attempt to connect to each server +# specified until successful. +function choose_server { + local num_servers=0 + local name + while read name server port remain do - # Examine the next service descriptor - # Is it a stap server? - (echo $REPLY | grep -q "^=.*_stap") || continue - - # Get the details of the service - local service_tag equal data - while read service_tag equal service_data - do - case $service_tag in - '=' ) - break ;; - hostname ) - server_name=`expr "$service_data" : '\[\([^]]*\)\]'` - ;; - address ) - # Sometimes (seems random), avahi-resolve-host-name resolves a local server to its - # hardware address rather its ip address. Keep trying until we get - # an ip address. - server_ip=`expr "$service_data" : '\[\([^]]*\)\]'` - local attempt - for ((attempt=0; $attempt < 5; ++attempt)) - do - server_ip=`expr "$server_ip" : '^\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\)$'` - if test "X$server_ip" != "X"; then - break - fi - # Resolve the server.domain to an ip address. - server_ip=`avahi-resolve-host-name $hostname` - server_ip=`expr "$server_ip" : '.* \(.*\)$'` - done - ;; - port ) - port=`expr "$service_data" : '\[\([^]]*\)\]'` - ;; - txt ) - sysinfo_server=`expr "$service_data" : '\[\"\([^]]*\)\"\]'` - ;; - * ) - break ;; - esac - done + num_servers=$(($num_servers + 1)) + + if test "X$server" = "X"; then + fatal "ERROR: server ip address not provided" + fi - # It is a stap server, but is it compatible? - if test "$sysinfo_server" != "`client_sysinfo`"; then - server_ip= - continue + if test "X$port" = "X"; then + fatal "ERROR: server port not provided" fi - if test "X$server_ip" != "X"; then - break + if connect_to_server $server $port; then + return 0 fi done - echo $server_ip/$port + if test num_servers = 0; then + fatal "ERROR: cannot find a server" + fi + + fatal "ERROR: unable to connect to a server" +} + +# function: connect_to_server IP PORT +# +# Establish connection with the given server +function connect_to_server { + # Open a connection to the server + exec 3<> /dev/tcp/$1/$2 } # function: disconnect_from_server @@ -568,15 +531,40 @@ function stream_output { # Call staprun using the module returned from the server, if requested. function maybe_call_staprun { if test $p_phase = 5; then + # Can't call staprun without a module. + test "X$tmpdir_stap" = "X" && return + + local mod_name=`ls $tmpdir_stap | grep '.ko$'` + test "X$mod_name" != "X" || \ + fatal "ERROR: no module to run in $tmpdir_stap" + + # We have a module. Try to run it for ((--v_level; $v_level > 0; --v_level)) do staprun_opts="$staprun_opts -v" done - staprun $staprun_opts \ + PATH=`staprun_PATH` staprun $staprun_opts \ $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'` fi } +# function: staprun_PATH +# +# Compute a PATH suitable for running staprun. +function staprun_PATH { + # staprun may invoke 'stap'. So we can use the current PATH if we were + # not invoked as 'stap' or we are not the first 'stap' on the PATH. + local first_stap=`which stap 2>/dev/null` + if test `which $0 2>/dev/null` != $first_stap; then + echo "$PATH" + return + fi + + # Otherwise, remove the PATH component where we live from the PATH + local PATH_component=`dirname $first_stap` + echo $PATH | sed "s,$PATH_component,,g" +} + # function: check_server_error SERVER_RESPONSE # # Check the given server response for an error message. @@ -591,6 +579,7 @@ function check_server_error { # Prints its arguments to stderr and exits function fatal { echo $0: "$@" >&2 + disconnect_from_server cleanup exit 1 } @@ -602,6 +591,7 @@ function fatal { function server_fatal { echo $0: "$@" >&2 cat <&3 >&2 + disconnect_from_server cleanup exit 1 } diff --git a/stap-find-or-start-server b/stap-find-or-start-server new file mode 100755 index 00000000..0ea0ef43 --- /dev/null +++ b/stap-find-or-start-server @@ -0,0 +1,36 @@ +#!/bin/bash + +# Find or start a systemtap server +# +# Copyright (C) 2008 Red Hat Inc. +# +# This file is part of systemtap, and is free software. You can +# redistribute it and/or modify it under the terms of the GNU General +# Public License (GPL); either version 2, or (at your option) any +# later version. + +# This script attempts to find a systemtap server. If one is found, it +# simply exits with 0. +# +# Otherwise, it attempts to start a server. If succesful, it echoes the +# process id and exits with 0. +# +# Otherwise, it exits with 1 + +# Is there a server available? +stap-find-servers >/dev/null 2>&1 && exit 0 + +# No server available, try to start one. +pid=`stap-start-server` +if test $? = 0; then + echo $pid + # Make sure the server is started + for ((attempt=0; $attempt < 5; ++attempt)) + do + stap-find-servers >/dev/null 2>&1 && exit 0 + sleep 1 + done +fi + +# Could not find or start a server +exit 1 diff --git a/stap-find-servers b/stap-find-servers new file mode 100755 index 00000000..9e7b633d --- /dev/null +++ b/stap-find-servers @@ -0,0 +1,128 @@ +#!/bin/bash + +# Find compile servers for systemtap +# +# Copyright (C) 2008 Red Hat Inc. +# +# This file is part of systemtap, and is free software. You can +# redistribute it and/or modify it under the terms of the GNU General +# Public License (GPL); either version 2, or (at your option) any +# later version. + +# This script uses avahi to find systemtap compile servers on the local +# network. Information about each server found is printed to stdout. + +#----------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------- +# function: configuration +function configuration { + avahi_service_tag=_stap._tcp +} + +# function: initialization +function initialization { + rc=1 # not found yet + if test "X$1" = "X--all"; then + find_all=1 + else + find_all=0 + fi +} + +# function: find_and_connect_to_server +# +# Find and establish connection with a compatibale stap server. +function find_servers { + # Find a server + avahi-browse $avahi_service_tag --terminate -r 2>/dev/null | match_server + rc=$? +} + +# function: match_server +# +# Find a suitable server using the avahi-browse output provided on stdin. +function match_server { + local server_ip + local server_name + local server_sysinfo + local server_port + local rc=1 # not found yet + + # Loop over the avahi service descriptors. + while read + do + # Examine the next service descriptor + # Is it a stap server? + (echo $REPLY | grep -q "^=.*_stap") || continue + + # Get the details of the service + local service_tag equal data + while read service_tag equal service_data + do + case $service_tag in + '=' ) + break ;; + hostname ) + server_name=`expr "$service_data" : '\[\([^]]*\)\]'` + ;; + address ) + # Sometimes (seems random), avahi-resolve-host-name resolves a local server to its + # hardware address rather its ip address. Keep trying until we get + # an ip address. + server_ip=`expr "$service_data" : '\[\([^]]*\)\]'` + local attempt + for ((attempt=0; $attempt < 5; ++attempt)) + do + server_ip=`expr "$server_ip" : '^\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\)$'` + if test "X$server_ip" != "X"; then + break + fi + # Resolve the server.domain to an ip address. + server_ip=`avahi-resolve-host-name $hostname` + server_ip=`expr "$server_ip" : '.* \(.*\)$'` + done + ;; + port ) + server_port=`expr "$service_data" : '\[\([^]]*\)\]'` + ;; + txt ) + server_sysinfo=`expr "$service_data" : '\[\"\([^]]*\)\"\]'` + ;; + * ) + break ;; + esac + done + + # It is a stap server, but is it compatible? + if test $find_all = 0 -a "$server_sysinfo" != "`client_sysinfo`"; then + continue + fi + + # It's compatible, or we're finding all servers. Print a summary line + echo $server_name $server_ip $server_port "'$server_sysinfo'" + rc=0 + done + + exit $rc +} + +# function client_sysinfo +# +# Generate the client's sysinfo and echo it to stdout +function client_sysinfo { + if test "X$sysinfo_client" = "X"; then + # Add some info from uname + sysinfo_client="`uname -rvm`" + fi + echo $sysinfo_client +} + +#----------------------------------------------------------------------------- +# Beginning of main line execution. +#----------------------------------------------------------------------------- +configuration +initialization "$@" +find_servers + +exit $rc diff --git a/stap-server b/stap-server index 16ffe8ee..e825c49a 100755 --- a/stap-server +++ b/stap-server @@ -13,6 +13,9 @@ # contained in the unpacked tree to build the requested systemtap kernel module. # This module is then written to stdout. +# Catch ctrl-c and other termination signals +trap 'terminate' SIGTERM SIGINT + #----------------------------------------------------------------------------- # Helper functions. #----------------------------------------------------------------------------- @@ -143,20 +146,20 @@ function check_compatibility { # function: read_data_file PREFIX # -# Find a file whose name matches '$1.??????' whose first line +# Find a file whose name is '$1' and whose first line # contents are '$1: .*'. Read and echo the first line. function read_data_file { - for f in `ls $1.??????` - do - read < $f - line=$REPLY - data=`expr "$line" : "$1: \\\(.*\\\)"` - if test "X$data" != "X"; then - echo $data - return - fi - done - fatal "ERROR: Data file for $1 not found" + test -f $1 || \ + fatal "ERROR: Data file $1 not found" + + read < $1 + line=$REPLY + data=`expr "$line" : "$1: \\\(.*\\\)"` + if test "X$data" != "X"; then + echo $data + return + fi + fatal "ERROR: Data in file $1 is incorrect" } # function: parse_options [ STAP-OPTIONS ] @@ -312,6 +315,7 @@ function call_stap { else server_p_phase=$p_phase fi + eval stap $cmdline -k -p $server_p_phase \ >> $tmpdir_server/stdout \ 2>> $tmpdir_server/stderr @@ -328,19 +332,21 @@ function create_response { tmpdir_line=`cat stderr | grep "Keeping temp"` tmpdir_stap=`expr "$tmpdir_line" : '.*"\(.*\)".*'` - # Remove the message about keeping th<e stap temp directory from stderr, unless + # Remove the message about keeping the stap temp directory from stderr, unless # the user did request to keep it. - if test $keep_temps != 1; then - sed -i "/^Keeping temp/d" stderr + if test "X$tmpdir_stap" != "X"; then + if test $keep_temps != 1; then + sed -i "/^Keeping temp/d" stderr + fi + + # Add the contents of the stap temp directory to the server output directory + ln -s $tmpdir_stap `basename $tmpdir_stap` fi # If the user specified -p5, remove the name of the kernel module from stdout. if test $p_phase = 5; then sed -i '/\.ko$/d' stdout fi - - # Add the contents of the stap temp directory to the server output directory - ln -s $tmpdir_stap `basename $tmpdir_stap` } # function: package_response @@ -404,6 +410,15 @@ function cleanup { fi } +# function: terminate +# +# Terminate gracefully. +function terminate { + # Clean up + cleanup + exit +} + #----------------------------------------------------------------------------- # Beginning of main line execution. #----------------------------------------------------------------------------- diff --git a/stap-serverd b/stap-serverd index eaaeda00..af4b2717 100755 --- a/stap-serverd +++ b/stap-serverd @@ -13,8 +13,8 @@ # incoming connections. When a connection is detected, the stap-server script # is run to handle the request. -# Catch ctrl-c -trap 'handle_sigint' SIGINT +# Catch ctrl-c and other termination signals +trap 'terminate' SIGTERM SIGINT #----------------------------------------------------------------------------- # Helper functions. @@ -61,7 +61,10 @@ function listen { # Loop forever accepting requests while true do - nc -l $port < $fifo_name | stap-server $((port + 1)) > $fifo_name 2>&1 + # Run this in the background and wait for it. This way any signals + # received (i.e. SIGTERM) will be processed. + nc -l $port < $fifo_name | stap-server $((port + 1)) > $fifo_name 2>&1 & + wait %nc done } @@ -74,13 +77,24 @@ function fatal { exit 1 } -# function: handle_sigint +# function: terminate # -# Terminate gracefully when SIGINT is received. -function handle_sigint { - echo "$0: received SIGINT. Exiting." +# Terminate gracefully. +function terminate { + echo "$0: Exiting" + + # Kill the running 'avahi-publish-service' job + kill -s SIGTERM %avahi-publish-service 2> /dev/null + wait %avahi-publish-service 2> /dev/null + + # Kill any running 'nc -l' job. + kill -s SIGTERM "%nc -l" 2> /dev/null + wait "%nc - l" 2> /dev/null + + # Clean up cd `dirname $tmpdir` rm -fr $tmpdir + exit } diff --git a/stap-start-server b/stap-start-server new file mode 100755 index 00000000..d143e269 --- /dev/null +++ b/stap-start-server @@ -0,0 +1,24 @@ +#!/bin/bash + +# Start a systemtap server +# +# Copyright (C) 2008 Red Hat Inc. +# +# This file is part of systemtap, and is free software. You can +# redistribute it and/or modify it under the terms of the GNU General +# Public License (GPL); either version 2, or (at your option) any +# later version. + +# This script attempts to start a systemtap server and echoes the +# process id, if successful. + +# start the server +stap-serverd </dev/null >/dev/null 2>&1 & +server_pid=$! + +# Exit if the server did not start ok +(ps | grep -q $server_pid) || exit 1 + +# The server started ok. Echo its process id. +echo $server_pid +exit 0 diff --git a/stap-stop-server b/stap-stop-server new file mode 100755 index 00000000..5afcf705 --- /dev/null +++ b/stap-stop-server @@ -0,0 +1,30 @@ +#!/bin/bash + +# Start a systemtap server +# +# Copyright (C) 2008 Red Hat Inc. +# +# This file is part of systemtap, and is free software. You can +# redistribute it and/or modify it under the terms of the GNU General +# Public License (GPL); either version 2, or (at your option) any +# later version. + +# This script attempts to stop a systemtap server with the +# given pid. + +# Get the process id. +pid=$1 +if test "X$pid" = "X"; then + echo "Usage: $0 PROCESS_ID" >&2 + exit 1 +fi + +# Verify that it is a systemtap server +(ps -a | grep stap-serverd | grep -q $pid) +if test $? != 0; then + echo "$pid is not a systemtap server" + exit 1 +fi + +# Try to kill the server +kill -s SIGTERM $pid diff --git a/stapprobes.5.in b/stapprobes.5.in index 700452a7..24075248 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -329,6 +329,19 @@ may be repeated to follow more levels of pointers. $var[N] indexes into an array. The index is given with a literal number. +.TP +$$vars +expands to a character string that is equivalent to +sprintf("parm1=%x ... parmN=%x var1=%x ... varN=%x", parm1, ..., parmN, +var1, ..., varN) +.TP +$$locals +expands to a character string that is equivalent to +sprintf("var1=%x ... varN=%x", var1, ..., varN) +.TP +$$parms +expands to a character string that is equivalent to +sprintf("parm1=%x ... parmN=%x", parm1, ..., parmN) .PP For ".return" probes, context variables other than the "$return" value itself are only available for the function call parameters. @@ -367,6 +380,8 @@ process(PID).syscall process("PATH").syscall process(PID).syscall.return process("PATH").syscall.return +process(PID).itrace +process("PATH").itrace .ESAMPLE .PP A @@ -391,6 +406,9 @@ A probe gets called when a thread described by PID or PATH returns from a system call. The system call number is available in the "$syscall" context variable. +A +.B .itrace +probe gets called for every single step of the process described by PID or PATH. .PP Note that .I PATH diff --git a/systemtap.base/itrace.exp b/systemtap.base/itrace.exp new file mode 100644 index 00000000..4b73ac1c --- /dev/null +++ b/systemtap.base/itrace.exp @@ -0,0 +1,102 @@ +# itrace test + +# Initialize variables +set utrace_support_found 0 +set exepath "[pwd]/ls_[pid]" + +set itrace1_script { + global instrs = 0 + probe begin { printf("systemtap starting probe\n") } + probe process("%s").itrace + { + instrs += 1 + if (instrs == 5) + exit() + } + + + probe end { printf("systemtap ending probe\n") + printf("itraced = %%d\n", instrs) + } +} +set itrace1_script_output "itraced = 5\r\n" + +set itrace2_script { + global instrs = 0, itrace_on = 0, start_timer = 0 + probe begin { start_timer = 1; printf("systemtap starting probe\n") } + probe process("%s").itrace if (itrace_on) + { + instrs += 1 + if (instrs == 5) + exit() + } + + + probe timer.ms(1) if (start_timer) + { + itrace_on = 1 + } + + probe timer.ms(10) if (start_timer) + { + itrace_on = 0 + } + probe end { printf("systemtap ending probe\n") + printf("itraced = %%d\n", instrs) + } +} +set itrace2_script_output "itraced = 5\r\n" + + +# Set up our own copy of /bin/ls, to make testing for a particular +# executable easy. We can't use 'ln' here, since we might be creating +# a cross-device link. We can't use 'ln -s' here, since the kernel +# resolves the symbolic link and reports that /bin/ls is being +# exec'ed (instead of our local copy). +if {[catch {exec cp /bin/ls $exepath} res]} { + fail "unable to copy /bin/ls: $res" + return +} + +# "load" generation function for stap_run. It spawns our own copy of +# /bin/ls, waits 5 seconds, then kills it. +proc run_ls_5_sec {} { + global exepath + + spawn $exepath + set exe_id $spawn_id + after 5000; + exec kill -INT -[exp_pid -i $exe_id] + return 0; +} + + +# Try to find utrace_attach symbol in /proc/kallsyms +set path "/proc/kallsyms" +if {! [catch {exec grep -q utrace_attach $path} dummy]} { + set utrace_support_found 1 +} + +set TEST_NAME "itrace1" +if {$utrace_support_found == 0} { + untested "$TEST_NAME : no kernel utrace support found" +} elseif {![installtest_p]} { + untested "$TEST_NAME : not installtest_p" +} else { + set script [format $itrace1_script $exepath] + stap_run $TEST_NAME run_ls_5_sec $itrace1_script_output -e $script +} + + +set TEST_NAME "itrace2" +if {$utrace_support_found == 0} { + untested "$TEST_NAME : no kernel utrace support found" +} elseif {![installtest_p]} { + untested "$TEST_NAME : not installtest_p" +} else { + set script [format $itrace2_script $exepath] + stap_run $TEST_NAME run_ls_5_sec $itrace2_script_output -e $script +} + +# Cleanup +exec rm -f $exepath diff --git a/systemtap.spec b/systemtap.spec index deec1d28..503022d1 100644 --- a/systemtap.spec +++ b/systemtap.spec @@ -178,6 +178,10 @@ exit 0 %{_bindir}/stap %{_bindir}/stap-server %{_bindir}/stap-serverd +%{_bindir}/stap-find-servers +%{_bindir}/stap-start-server +%{_bindir}/stap-find-or-start-server +%{_bindir}/stap-stop-server %{_mandir}/man1/* %{_mandir}/man5/* diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 29c10507..b2592e1e 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,17 @@ + +2008-08-04 Wenji Huang <wenji.huang@oracle.com> + + * syscall.stp: Change $path to $pathname for 2.6.27. + * syscall2.stp: Ditto. + +2008-08-03 Wenji Huang <wenji.huang@oracle.com> + + * vfs.stp(add_to_page_cache): Correct for 2.6.27. + +2008-07-25 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls2.stp: Add sys_unlinkat. + 2008-07-18 Zhaolei <zhaolei@cn.fujitsu.com> * syscalls2.stp: Add sys_symlinkat. diff --git a/tapset/syscalls.stp b/tapset/syscalls.stp index 11c2bdf7..7fd942af 100644 --- a/tapset/syscalls.stp +++ b/tapset/syscalls.stp @@ -1715,13 +1715,21 @@ probe syscall.getuid.return = # void __user *value, size_t size) probe syscall.getxattr = kernel.function("sys_getxattr") { name = "getxattr" +%( kernel_v > "2.6.26" %? + path = user_string($pathname) +%: path = user_string($path) +%) # FIXME name2 = user_string($name) value_uaddr = $value size = $size argstr = sprintf("%s, %s, %p, %d", +%( kernel_v > "2.6.26" %? + user_string_quoted($pathname), +%: user_string_quoted($path), +%) user_string_quoted($name), value_uaddr, size) } @@ -1754,11 +1762,18 @@ probe syscall.init_module.return = kernel.function("sys_init_module").return ? { probe syscall.inotify_add_watch = kernel.function("sys_inotify_add_watch") ? { name = "inotify_add_watch" fd = $fd + mask = $mask +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) + argstr = sprintf("%d, %s, %d", $fd, user_string_quoted($pathname), $mask) +%: path_uaddr = $path path = user_string($path) - mask = $mask argstr = sprintf("%d, %s, %d", $fd, user_string_quoted($path), $mask) +%) } + probe syscall.inotify_add_watch.return = kernel.function("sys_inotify_add_watch").return ? { name = "inotify_add_watch" retstr = returnstr(1) @@ -2081,13 +2096,21 @@ probe syscall.lchown16.return = kernel.function("sys_lchown16").return ? { # probe syscall.lgetxattr = kernel.function("sys_lgetxattr") { name = "lgetxattr" +%( kernel_v > "2.6.26" %? + path = user_string($pathname) +%: path = user_string($path) +%) # FIXME name2 = user_string($name) value_uaddr = $value size = $size argstr = sprintf("%s, %s, %p, %d", +%( kernel_v > "2.6.26" %? + user_string_quoted($pathname), +%: user_string_quoted($path), +%) user_string_quoted($name), value_uaddr, size) } @@ -2156,11 +2179,17 @@ probe syscall.listen.return = kernel.function("sys_listen").return ? { # probe syscall.listxattr = kernel.function("sys_listxattr") { name = "listxattr" - path_uaddr = $path - path = user_string($path) list_uaddr = $list size = $size +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) + argstr = sprintf("%s, %p, %d", user_string_quoted($pathname), $list, $size) +%: + path_uaddr = $path + path = user_string($path) argstr = sprintf("%s, %p, %d", user_string_quoted($path), $list, $size) +%) } probe syscall.listxattr.return = kernel.function("sys_listxattr").return { name = "listxattr" @@ -2172,11 +2201,17 @@ probe syscall.listxattr.return = kernel.function("sys_listxattr").return { # probe syscall.llistxattr = kernel.function("sys_llistxattr") { name = "llistxattr" - path_uaddr = $path - path = user_string($path) list_uaddr = $list size = $size +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) + argstr = sprintf("%s, %p, %d", user_string_quoted($pathname), $list, $size) +%: + path_uaddr = $path + path = user_string($path) argstr = sprintf("%s, %p, %d", user_string_quoted($path), $list, $size) +%) } probe syscall.llistxattr.return = kernel.function("sys_llistxattr").return { name = "llistxattr" @@ -2225,11 +2260,17 @@ probe syscall.lookup_dcookie.return = kernel.function("sys_lookup_dcookie").retu # probe syscall.lremovexattr = kernel.function("sys_lremovexattr") { name = "lremovexattr" - path_uaddr = $path - path = user_string($path) name_uaddr = $name name2 = user_string($name) +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) + argstr = sprintf("%s, %s", user_string_quoted($pathname), user_string_quoted($name)) +%: + path_uaddr = $path + path = user_string($path) argstr = sprintf("%s, %s", user_string_quoted($path), user_string_quoted($name)) +%) } probe syscall.lremovexattr.return = kernel.function("sys_lremovexattr").return { name = "lremovexattr" @@ -2261,15 +2302,24 @@ probe syscall.lseek.return = kernel.function("sys_lseek").return { # probe syscall.lsetxattr = kernel.function("sys_lsetxattr") { name = "lsetxattr" +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) +%: path_uaddr = $path path = user_string($path) +%) name_uaddr = $name name_str = user_string($name) value_uaddr = $value size = $size flags = $flags argstr = sprintf("%s, %s, %p, %d, %d", +%( kernel_v > "2.6.26" %? + user_string_quoted($pathname), +%: user_string_quoted($path), +%) user_string_quoted($name), value_uaddr, $size, $flags) } diff --git a/tapset/syscalls2.stp b/tapset/syscalls2.stp index 910193ef..57d190e3 100644 --- a/tapset/syscalls2.stp +++ b/tapset/syscalls2.stp @@ -623,12 +623,17 @@ probe syscall.readlink.return = kernel.function("sys_readlink").return { probe syscall.readlinkat = kernel.function("sys_readlinkat") ? { name = "readlinkat" dfd = $dfd - path = user_string($path) buf_uaddr = $buf bufsiz = $bufsiz - argstr = sprintf("%s, %s, %p, %d", _dfd_str($dfd), user_string_quoted($path), - $buf, $bufsiz) +%( kernel_v > "2.6.26" %? + path = user_string($pathname) + argstr = sprintf("%s, %s, %p, %d", _dfd_str($dfd), user_string_quoted($pathname), $buf, $bufsiz) +%: + path = user_string($path) + argstr = sprintf("%s, %s, %p, %d", _dfd_str($dfd), user_string_quoted($path), $buf, $bufsiz) +%) } + probe syscall.readlinkat.return = kernel.function("sys_readlinkat").return ? { name = "readlinkat" retstr = returnstr(1) @@ -806,10 +811,17 @@ probe syscall.remap_file_pages.return = # probe syscall.removexattr = kernel.function("sys_removexattr") { name = "removexattr" - path = user_string($path) name_str = user_string($name) +%( kernel_v > "2.6.26" %? + path = user_string($pathname) + argstr = sprintf("%s, %s", user_string_quoted($pathname), + user_string_quoted($name)) +%: + path = user_string($path) argstr = sprintf("%s, %s", user_string_quoted($path), user_string_quoted($name)) +%) + } probe syscall.removexattr.return = kernel.function("sys_removexattr").return { name = "removexattr" @@ -1978,15 +1990,24 @@ probe syscall.setuid.return = # probe syscall.setxattr = kernel.function("sys_setxattr") { name = "setxattr" +%( kernel_v > "2.6.26" %? + path_uaddr = $pathname + path = user_string($pathname) +%: path_uaddr = $path path = user_string($path) +%) name_uaddr = $name name_str = user_string($name) value_uaddr = $value size = $size flags = $flags argstr = sprintf("%s, %s, %p, %d, %d", +%( kernel_v > "2.6.26" %? + user_string_quoted($pathname), +%: user_string_quoted($path), +%) user_string_quoted($name), value_uaddr, $size, $flags) } @@ -2376,10 +2397,16 @@ probe syscall.statfs = kernel.function("compat_sys_statfs") ? { name = "statfs" - path = user_string($path) buf_uaddr = $buf +%( kernel_v > "2.6.26" %? + path = user_string($pathname) + argstr = sprintf("%s, %p", user_string_quoted($pathname), $buf) +%: + path = user_string($path) argstr = sprintf("%s, %p", user_string_quoted($path), $buf) +%) } + probe syscall.statfs.return = kernel.function("sys_statfs").return, kernel.function("compat_sys_statfs").return ? @@ -2398,11 +2425,17 @@ probe syscall.statfs64 = kernel.function("compat_sys_statfs64") ? { name = "statfs" - path = user_string($path) sz = $sz buf_uaddr = $buf +%( kernel_v > "2.6.26" %? + path = user_string($pathname) + argstr = sprintf("%s, %d, %p", user_string_quoted($pathname), $sz, $buf) +%: + path = user_string($path) argstr = sprintf("%s, %d, %p", user_string_quoted($path), $sz, $buf) +%) } + probe syscall.statfs64.return = kernel.function("sys_statfs64").return ?, kernel.function("compat_sys_statfs64").return ? @@ -2899,6 +2932,25 @@ probe syscall.unlink.return = kernel.function("sys_unlink").return { retstr = returnstr(1) } +# unlinkat ___________________________________________________ +# new function with 2.6.16 +# long sys_unlinkat(int dfd, const char __user *pathname, +# int flag) +probe syscall.unlinkat = kernel.function("sys_unlinkat") ? { + name = "unlinkat" + dfd = $dfd + dfd_str = _dfd_str($dfd) + pathname = $pathname + pathname_str = user_string($pathname) + flag = $flag + flag_str = _at_flag_str($flag) + argstr = sprintf("%s, %s, %s", dfd_str, user_string_quoted($pathname), flag_str) +} +probe syscall.unlinkat.return = kernel.function("sys_unlinkat").return ? { + name = "unlinkat" + retstr = returnstr(1) +} + # unshare ____________________________________________________ # new function with 2.6.16 # long sys_unshare(unsigned long unshare_flags) diff --git a/tapset/vfs.stp b/tapset/vfs.stp index 46bc3d21..1ea8fc8e 100644 --- a/tapset/vfs.stp +++ b/tapset/vfs.stp @@ -744,7 +744,11 @@ probe vfs.do_mpage_readpage.return = kernel.function ("do_mpage_readpage").retur units = "pages" } +%( kernel_v > "2.6.26" %? +probe vfs.add_to_page_cache = kernel.function ("add_to_page_cache_locked") +%: probe vfs.add_to_page_cache = kernel.function ("add_to_page_cache") +%) { dev = $mapping->host->i_sb->s_dev devname = __find_bdevname(dev, $mapping->host->i_sb->s_bdev) @@ -756,7 +760,12 @@ probe vfs.add_to_page_cache = kernel.function ("add_to_page_cache") name = "vfs.add_to_page_cache" argstr = sprintf("%d, %d", ino, index) } + +%( kernel_v > "2.6.26" %? +probe vfs.add_to_page_cache.return = kernel.function ("add_to_page_cache_locked").return +%: probe vfs.add_to_page_cache.return = kernel.function ("add_to_page_cache").return +%) { name = "vfs.add_to_page_cache" retstr = sprintf("%d", $return) diff --git a/tapsets.cxx b/tapsets.cxx index b9b4fcff..d06f7cea 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2485,7 +2485,7 @@ struct dwarf_query : public base_query // It arises because we sometimes try to fix up slightly-off // .statement() probes (something we find out in fairly low-level). // -// An alternative would be to put some more intellgence into query_cu(), +// An alternative would be to put some more intelligence into query_cu(), // and have it print additional suggestions after finding that // q->dw.iterate_over_srcfile_lines resulted in no new finished_results. @@ -4285,6 +4285,84 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) return; } + if (e->base_name == "$$vars" + || e->base_name == "$$parms" + || e->base_name == "$$locals") + { + Dwarf_Die *scopes; + if (dwarf_getscopes_die (scope_die, &scopes) == 0) + return; + + target_symbol *tsym = new target_symbol; + print_format* pf = new print_format; + + // Convert $$parms to sprintf of a list of parms and active local vars + // which we recursively evaluate + token* tmp_tok = new token; + tmp_tok->type = tok_identifier; + tmp_tok->content = "sprintf"; + pf->tok = tmp_tok; + pf->print_to_stream = false; + pf->print_with_format = true; + pf->print_with_delim = false; + pf->print_with_newline = false; + pf->print_char = false; + + Dwarf_Die result; + if (dwarf_child (&scopes[0], &result) == 0) + do + { + switch (dwarf_tag (&result)) + { + case DW_TAG_variable: + if (e->base_name == "$$parms") + continue; + break; + case DW_TAG_formal_parameter: + if (e->base_name == "$$locals") + continue; + break; + + default: + continue; + } + + const char *diename = dwarf_diename (&result); + token* sym_tok = new token; + sym_tok->location = e->get_tok()->location; + sym_tok->type = tok_identifier; + sym_tok->content = diename; + tsym->tok = sym_tok; + tsym->base_name = "$"; + tsym->base_name += diename; + Dwarf_Attribute attr_mem; + + // Ignore any variable that isn't accessible. + // dwarf_attr_integrate is checked by literal_stmt_for_local + // dwarf_getlocation_addr is checked by translate_location + // but if those fail we cannot catch semantic_error. + if (dwarf_attr_integrate (&result, DW_AT_location, &attr_mem) != NULL) + { + Dwarf_Op *expr; + size_t len; + if (dwarf_getlocation_addr (&attr_mem, addr - q.dw.module_bias, + &expr, &len, 1) == 0) + continue; + this->visit_target_symbol(tsym); + pf->raw_components += diename; + pf->raw_components += "=%#x "; + pf->args.push_back(*(expression**)this->targets.top()); + } + } + while (dwarf_siblingof (&result, &result) == 0); + + pf->raw_components += "\\n"; + pf->components = print_format::string_to_components(pf->raw_components); + provide <print_format*> (this, pf); + + return; + } + // Synthesize a function. functiondecl *fdecl = new functiondecl; fdecl->tok = e->tok; @@ -5376,6 +5454,280 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "stap_stop_task_finder();"; } +// ------------------------------------------------------------------------ +// itrace user-space probes +// ------------------------------------------------------------------------ + + +struct itrace_derived_probe: public derived_probe +{ + bool has_path; + string path; + int64_t pid; + int single_step; + + itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, + bool hp, string &pn, int64_t pd, int ss + ); + void join_group (systemtap_session& s); +}; + + +struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe> +{ +private: + map<string, vector<itrace_derived_probe*> > probes_by_path; + typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator; + map<int64_t, vector<itrace_derived_probe*> > probes_by_pid; + typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator; + unsigned num_probes; + + void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p); + +public: + itrace_derived_probe_group(): num_probes(0) { } + + void enroll (itrace_derived_probe* probe); + void emit_module_decls (systemtap_session& s); + void emit_module_init (systemtap_session& s); + void emit_module_exit (systemtap_session& s); +}; + + +itrace_derived_probe::itrace_derived_probe (systemtap_session &s, + probe* p, probe_point* l, + bool hp, string &pn, int64_t pd, + int ss + ): + derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss) +{ +} + + +void +itrace_derived_probe::join_group (systemtap_session& s) +{ + if (! s.itrace_derived_probes) + s.itrace_derived_probes = new itrace_derived_probe_group (); + + s.itrace_derived_probes->enroll (this); + + task_finder_derived_probe_group::create_session_group (s); +} + +struct itrace_builder: public derived_probe_builder +{ + itrace_builder() {} + virtual void build(systemtap_session & sess, + probe * base, + probe_point * location, + std::map<std::string, literal *> const & parameters, + vector<derived_probe *> & finished_results) + { + string path; + int64_t pid; + int single_step; + + bool has_path = get_param (parameters, TOK_PROCESS, path); + bool has_pid = get_param (parameters, TOK_PROCESS, pid); + assert (has_path || has_pid); + + single_step = 1; + + // If we have a path, we need to validate it. + if (has_path) + { + string::size_type start_pos, end_pos; + string component; + + // Make sure it starts with '/'. + if (path[0] != '/') + throw semantic_error ("process path must start with a '/'", + location->tok); + + start_pos = 1; // get past the initial '/' + while ((end_pos = path.find('/', start_pos)) != string::npos) + { + component = path.substr(start_pos, end_pos - start_pos); + // Make sure it isn't empty. + if (component.size() == 0) + throw semantic_error ("process path component cannot be empty", + location->tok); + // Make sure it isn't relative. + else if (component == "." || component == "..") + throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); + + start_pos = end_pos + 1; + } + component = path.substr(start_pos); + // Make sure it doesn't end with '/'. + if (component.size() == 0) + throw semantic_error ("process path cannot end with a '/'", location->tok); + // Make sure it isn't relative. + else if (component == "." || component == "..") + throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); + } + + finished_results.push_back(new itrace_derived_probe(sess, base, location, + has_path, path, pid, + single_step + )); + } +}; + + +void +itrace_derived_probe_group::enroll (itrace_derived_probe* p) +{ + if (p->has_path) + probes_by_path[p->path].push_back(p); + else + probes_by_pid[p->pid].push_back(p); + num_probes++; + + // XXX: multiple exec probes (for instance) for the same path (or + // pid) should all share a itrace report function, and have their + // handlers executed sequentially. +} + + +void +itrace_derived_probe_group::emit_probe_decl (systemtap_session& s, + itrace_derived_probe *p) +{ + s.op->newline() << "{"; + s.op->line() << " .tgt={"; + + if (p->has_path) + { + s.op->line() << " .pathname=\"" << p->path << "\","; + s.op->line() << " .pid=0,"; + } + else + { + s.op->line() << " .pathname=NULL,"; + s.op->line() << " .pid=" << p->pid << ","; + } + + s.op->line() << " .callback=&_stp_itrace_probe_cb,"; + s.op->line() << " },"; + s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; + s.op->line() << " .single_step=" << p->single_step << ","; + s.op->line() << " .ph=&" << p->name << ","; + + s.op->line() << " },"; +} + + +void +itrace_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) + return; + + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + s.op->newline() << "struct stap_itrace_probe {"; + s.op->indent(1); + s.op->newline() << "struct stap_task_finder_target tgt;"; + s.op->newline() << "const char *pp;"; + s.op->newline() << "void (*ph) (struct context*);"; + s.op->newline() << "int single_step;"; + s.op->newline(-1) << "};"; + s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);"; + s.op->newline() << "#include \"itrace.c\""; + + // output routine to call itrace probe + s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {"; + s.op->indent(1); + + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); + s.op->newline() << "c->probe_point = p->pp;"; + s.op->newline() << "c->regs = regs;"; + s.op->newline() << "c->data = data;"; + + // call probe function + s.op->newline() << "(*p->ph) (c);"; + common_probe_entryfn_epilogue (s.op); + + s.op->newline() << "return;"; + s.op->newline(-1) << "}"; + + // Output task finder callback routine that gets called for all + // itrace probe types. + s.op->newline() << "static int _stp_itrace_probe_cb(struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {"; + s.op->indent(1); + s.op->newline() << "int rc = 0;"; + s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);"; + + s.op->newline() << "if (register_p) "; + s.op->indent(1); + + s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);"; + s.op->newline(-1) << "else"; + s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));"; + s.op->newline(-1) << "return rc;"; + s.op->newline(-1) << "}"; + + s.op->newline() << "struct stap_itrace_probe stap_itrace_probes[] = {"; + s.op->indent(1); + + // Set up 'process(PATH)' probes + if (! probes_by_path.empty()) + { + for (p_b_path_iterator it = probes_by_path.begin(); + it != probes_by_path.end(); it++) + { + for (unsigned i = 0; i < it->second.size(); i++) + { + itrace_derived_probe *p = it->second[i]; + emit_probe_decl(s, p); + } + } + } + + // Set up 'process(PID)' probes + if (! probes_by_pid.empty()) + { + for (p_b_pid_iterator it = probes_by_pid.begin(); + it != probes_by_pid.end(); it++) + { + for (unsigned i = 0; i < it->second.size(); i++) + { + itrace_derived_probe *p = it->second[i]; + emit_probe_decl(s, p); + } + } + } + s.op->newline(-1) << "};"; +} + + +void +itrace_derived_probe_group::emit_module_init (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) + return; + + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + + s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {"; + s.op->indent(1); + s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];"; + s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);"; + s.op->newline(-1) << "}"; +} + + +void +itrace_derived_probe_group::emit_module_exit (systemtap_session& s) +{ + if (probes_by_path.empty() && probes_by_pid.empty()) return; + s.op->newline(); + s.op->newline() << "/* ---- itrace probes ---- */"; + s.op->newline() << "cleanup_usr_itrace();"; +} // ------------------------------------------------------------------------ // utrace user-space probes @@ -8723,6 +9075,13 @@ register_standard_tapsets(systemtap_session & s) ->bind(new utrace_builder ()); s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) ->bind(new utrace_builder ()); + + // itrace user-space probes + s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace") + ->bind(new itrace_builder ()); + s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace") + ->bind(new itrace_builder ()); + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL) ->bind(new utrace_builder ()); s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL) @@ -8774,6 +9133,7 @@ all_session_groups(systemtap_session& s) // "register" the dummy task_finder probe group after all probe // groups that use the task_finder. DOONE(utrace); + DOONE(itrace); DOONE(task_finder); #undef DOONE return g; diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 14243b80..9dd388ad 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,28 @@ +2008-08-05 Stan Cox <scox@redhat.com> + + * systemtap.base/warnings.stp: Use relative instead of absolute line. + * systemtap.base/vars.exp: New test. + +2008-08-03 Wenji Huang <wenji.huang@oracle.com> + + * buildok/seven.stp: Correct for 2.6.27. + * buildok/seventeen.stp: Ditto. + +2008-07-29 Dave Brolley <brolley@redhat.com> + + * Makefile.am (SYSTEMTAP_PATH): Add $(EXTRA_SYSTEMTAP_PATH). + * lib/stap_compile.exp: Revert previous change. + * lib/stap_run.exp: Likewise. + * lib/stap_run2.exp: Likewise. + * lib/stap_run_binary.exp: Likewise. + * lib/stap_run_exact.exp: Likewise. + * lib/systemtap.exp (stap_exec): Removed. + * Makefile.in: Regenerated. + +2008-07-24 Dave Nomura <dcnltc@us.ibm.com> + + * systemtap.base/itrace.stp: Added simple tests of itrace probe. + 2008-07-14 Dave Brolley <brolley@redhat.com> * Makefile.am (TOOL_OPTS): New variable. diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 5f3044cd..03c70cb6 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -40,7 +40,7 @@ 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) +SYSTEMTAP_PATH=$(EXTRA_SYSTEMTAP_PATH):$(DESTDIR)$(bindir) RUNTESTDEFAULTFLAGS = --tool $$tool --tool_opts \'$(TOOL_OPTS)\' --srcdir $$srcdir EXPECT = expect diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 8fe7a21f..cc23aed4 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -149,7 +149,7 @@ 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) +SYSTEMTAP_PATH = $(EXTRA_SYSTEMTAP_PATH):$(DESTDIR)$(bindir) RUNTESTDEFAULTFLAGS = --tool $$tool --tool_opts \'$(TOOL_OPTS)\' --srcdir $$srcdir EXPECT = expect RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH $(srcdir)/execrc runtest" diff --git a/testsuite/buildok/seven.stp b/testsuite/buildok/seven.stp index d6f6e5a9..dc3bc786 100755 --- a/testsuite/buildok/seven.stp +++ b/testsuite/buildok/seven.stp @@ -6,6 +6,7 @@ # first: enums and ints +%( kernel_v <= "2.6.26" %? probe kernel.function("find_pid") { %( kernel_v >= "2.6.17" %? @@ -15,6 +16,7 @@ probe kernel.function("find_pid") . sprint($nr) . ")") %) } +%) # second: opaque pointers and enums diff --git a/testsuite/buildok/seventeen.stp b/testsuite/buildok/seventeen.stp index 9adffa48..e4a7a8e8 100755 --- a/testsuite/buildok/seventeen.stp +++ b/testsuite/buildok/seventeen.stp @@ -5,5 +5,9 @@ probe kernel.function("pipe_write") { +%( kernel_v > "2.6.26" %? + printf("0x%x\n", $write_pipefifo_fops->llseek) +%: printf("0x%x\n", $write_fifo_fops->llseek) +%) } diff --git a/testsuite/lib/stap_compile.exp b/testsuite/lib/stap_compile.exp index 8f82018f..35124a44 100644 --- a/testsuite/lib/stap_compile.exp +++ b/testsuite/lib/stap_compile.exp @@ -4,7 +4,7 @@ # - script is the script to compile # Additional arguments are passed to stap as-is. proc stap_compile { TEST_NAME compile script args } { - set cmd [concat [stap_exec] {-v -p4 -e} $script $args] + set cmd [concat stap {-v -p4 -e} $script $args] verbose -log "running $cmd" eval spawn $cmd diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index 5f67d773..c0027e95 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -26,7 +26,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return } - set cmd [concat [stap_exec] -v $args] + set cmd [concat stap -v $args] if [file readable $test_file_name] { lappend cmd $test_file_name } diff --git a/testsuite/lib/stap_run2.exp b/testsuite/lib/stap_run2.exp index 1d9dc0b3..9849aefb 100644 --- a/testsuite/lib/stap_run2.exp +++ b/testsuite/lib/stap_run2.exp @@ -15,7 +15,7 @@ proc stap_run2 { TEST_NAME args } { if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return } - set cmd [concat [stap_exec] $args $test_file_name] + set cmd [concat stap $args $test_file_name] catch {eval exec $cmd} res set n 0 diff --git a/testsuite/lib/stap_run_binary.exp b/testsuite/lib/stap_run_binary.exp index a5e1195a..1d31d817 100644 --- a/testsuite/lib/stap_run_binary.exp +++ b/testsuite/lib/stap_run_binary.exp @@ -13,7 +13,7 @@ proc stap_run_binary { TEST_NAME} { if {[info procs installtest_p] != "" && ![installtest_p]} {untested $TEST_NAME; return} set hex_args {-ve 8/1 "%02x " "\n"} - set res [exec [stap_exec] $test_file_name | hexdump $hex_args] + set res [exec stap $test_file_name | hexdump $hex_args] if {[string compare $res $::result_string] == 0} { pass "$TEST_NAME" diff --git a/testsuite/lib/stap_run_exact.exp b/testsuite/lib/stap_run_exact.exp index 23c22ec0..6a473798 100644 --- a/testsuite/lib/stap_run_exact.exp +++ b/testsuite/lib/stap_run_exact.exp @@ -12,7 +12,7 @@ proc stap_run_exact { TEST_NAME test_file_name args } { if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return } - set cmd [concat [stap_exec] $args $test_file_name] + set cmd [concat stap $args $test_file_name] catch {eval exec $cmd} res set n 0 diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index e74bd13c..db5c1587 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -16,15 +16,6 @@ proc use_server_p {} { } -proc stap_exec {} { - if {[info procs use_server_p] != "" && [use_server_p]} then { - return "stap-client" - } else { - return "stap" - } -} - - proc print_systemtap_version {} { set version [exec /bin/uname -r] set location "/boot/vmlinux-$version" diff --git a/testsuite/systemtap.base/vars.exp b/testsuite/systemtap.base/vars.exp new file mode 100644 index 00000000..7541c01b --- /dev/null +++ b/testsuite/systemtap.base/vars.exp @@ -0,0 +1,32 @@ +# Script for testing $$vars, $$parms, $$locals + +set test "vars" + +# grab C statement that $$vars yields +set cmd [concat stap -p3 -e {"probe kernel.statement(\"bio_copy_user@fs/bio.c+1\") \{print (\$\$vars)\}"} 2>&1 | grep {"printf.*="} | sed -e {"s/^.*MAXSTRINGLEN, \"//"} -e {s/..\".*$//}] +catch {eval exec $cmd} vars + +# grab C statement that $$parms yields +set cmd [regsub "vars" $cmd "parms"] +catch {eval exec $cmd} parms + +# grab C statement that $$locals yields +set cmd [regsub "parms" $cmd "locals"] +catch {eval exec $cmd} locals + +# syntax check of $$vars C statement +set vars_ok [regexp "(\[a-z_\]+=%#llx *)+" $vars] +if {!$vars_ok} { + fail "$test" +} else { + pass "$test" +} + +# $$vars should be equivalent to $$parms + $$locals +if {![string equal [string trim $vars] \ + [string trim [concat $parms " " $locals]]]} { + fail "$test parms/locals" +} else { + pass "$test parms/locals" +} + diff --git a/testsuite/systemtap.base/warnings.stp b/testsuite/systemtap.base/warnings.stp index 94ed57b3..d71b3034 100644 --- a/testsuite/systemtap.base/warnings.stp +++ b/testsuite/systemtap.base/warnings.stp @@ -9,7 +9,7 @@ probe never { print(elide+me1) bar () } # PR 6611 -probe probea = kernel.statement("bio_init@fs/bio.c:135") +probe probea = kernel.statement("bio_init@fs/bio.c+3") { printf("%d", funca(2)); elide_me6="foo" } probe probea { printf("%d", funcb(2,3)); printf("%s",var) } diff --git a/testsuite/systemtap.examples/ChangeLog b/testsuite/systemtap.examples/ChangeLog index d75ad014..7cb39fb9 100644 --- a/testsuite/systemtap.examples/ChangeLog +++ b/testsuite/systemtap.examples/ChangeLog @@ -1,3 +1,11 @@ +2008-08-01 William Cohen <wcohen@redhat.com> + + * helloworld.meta, traceio2.meta: Tweak test_installcheck. + +2008-08-01 William Cohen <wcohen@redhat.com> + + * check.exp: Run both tests for installcheck tests. + 2008-07-11 Mark Wielaard <mwielaard@redhat.com> * traceio.meta: s/decending/descending/ in description. diff --git a/testsuite/systemtap.examples/check.exp b/testsuite/systemtap.examples/check.exp index 2ac43050..14d9a57e 100644 --- a/testsuite/systemtap.examples/check.exp +++ b/testsuite/systemtap.examples/check.exp @@ -32,6 +32,23 @@ proc extract_tag { META_DATA TAG } { return $value } +proc run_command { test command } { + #FIXME tcl says that single quotes not dealt with + if { $command != "" } then { + verbose -log "attempting command $command" + set res [catch {eval exec $command} value] + verbose -log "OUT $value" + verbose -log "RC $res" + if {$res != 0 } { + fail $test + } else { + pass $test + } + } else { + untested $test + } +} + set curdir [pwd] set src_examples $srcdir/systemtap.examples @@ -39,36 +56,21 @@ set meta_files [lsort [exec find $src_examples -path "*.meta"]] foreach file $meta_files { set dir [file dirname $file] set test [regsub {.*/testsuite/} $file ""] + set test [regsub {.meta} $test ""] cd $dir set meta_data [get_meta_data $file] set test_check [extract_tag "$meta_data" "test_check"] + set command $test_check + run_command "$test build" $command set test_installcheck [extract_tag "$meta_data" "test_installcheck"] - # Would like to run the tests (-p5), but pass fail logic too - # simple and fails for many examples - # FIXME following line prevents installcheck with "--tools_opts install" - set test_installcheck "" + # The pass/fail logic too simple and fails for some examples + # FIXME would like to be able to run more complicated test code if {[info procs installtest_p] != "" && [installtest_p] && $test_installcheck != "" } then { set command $test_installcheck - } else { - set command $test_check - } - - #FIXME tcl says that single quotes not dealt with - if { $command != "" } then { - verbose -log "attempting command $command" - set res [catch {eval exec $command} value] - verbose -log "OUT $value" - verbose -log "RC $res" - if {$res != 0 } { - fail $test - } else { - pass $test - } - } else { - untested $test + run_command "$test run" $command } } diff --git a/testsuite/systemtap.examples/helloworld.meta b/testsuite/systemtap.examples/helloworld.meta index f56b7ca3..60bc53f2 100644 --- a/testsuite/systemtap.examples/helloworld.meta +++ b/testsuite/systemtap.examples/helloworld.meta @@ -10,4 +10,4 @@ output: text scope: system-wide description: A basic "Hello World" program implemented in SystemTap script. It prints out "hello world" message and then immediately exits. test_check: stap -p4 helloworld.stp -test_installcheck: stap helloworld.stp -c "sleep 1" +test_installcheck: stap helloworld.stp diff --git a/testsuite/systemtap.examples/traceio2.meta b/testsuite/systemtap.examples/traceio2.meta index e6bca1a9..4b63108c 100644 --- a/testsuite/systemtap.examples/traceio2.meta +++ b/testsuite/systemtap.examples/traceio2.meta @@ -10,4 +10,4 @@ output: trace scope: system-wide description: Print out the executable name and process number as reads and writes to the specified device occur. test_check: stap -p4 traceio2.stp 0x0801 -test_installcheck: /bin/sh eval stap traceio2.stp 0x0801 -c "sleep 1" +test_installcheck: stap traceio2.stp 0x0801 -c "sleep 1" |