diff options
218 files changed, 6167 insertions, 8685 deletions
@@ -3,6 +3,7 @@ *# .#* autom4te.* +cscope.files cscope*out config.h config.log @@ -1,3 +1,344 @@ +2008-06-23 Frank Ch. Eigler <fche@elastic.org> + + * session.h (module_cache): Add field here. + * tapsets.cxx (dwflpp): Remove static field from here. + (pathname_caching_callback): Use hacky micro-static to get to it. + (*): Update other users of module_cache. + * elaborate.cxx (systemtap_session ctor): Corresponding changes. + +2008-06-23 David Smith <dsmith@redhat.com> + + * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl): + Handles UDPF_NONE value. + (utrace_derived_probe_group::emit_vm_callback_probe_decl): New + function. + (utrace_derived_probe_group::emit_module_decls): Calls + emit_vm_callback_probe_decl() to set up vm_callbacks. + +2008-06-23 Stan Cox <scox@redhat.com> + + * NEWS: Updated .statement line number wildcard and line number range. + * stapprobes.5.in: Likewise. + * doc/langref.tex: Likewise. + * tapsets.cxx (enum line_t): Add RANGE and WILDCARD. + (iterate_over_srcfile_lines): Change lineno parm to lines[]. + Support RANGE and WILDCARD. + (dwarf_query): Change line to line[] + (dwarf_query::parse_function_spec): Parse RANGE and WILDCARD. + +2008-06-20 wcohen <wcohen@redhat.com> + + * stapfuncs.5.in: Add documentation for tapset/dev.stp functions. + +2008-06-18 Josh Stone <joshua.i.stone@intel.com> + + PR 6644 + * elaborate.cxx (dead_stmtexpr_remover::visit_block): Flatten nested + block statements into a single block. + (dead_stmtexpr_remover::visit_if_statement): Remove the possibility + of if_statements with a null thenblock. When an if lacks both then + and else, either remove it completely or reduce it to a simple + statment evaluating the condition. With an else and no then, invert + the condition and else becomes then. + (void_statement_reducer): New optimization visitor that breaks + statements in void context into smaller pieces, to expose more + optimization opportunities. + (semantic_pass_opt5, semantic_pass_opt6): Bump opt5 to opt6, and + create a new opt5 that runs through void_statement_reducer. + +2008-06-16 Frank Ch. Eigler <fche@elastic.org> + + * tapsets.cxx (print_locals): Produce nothing instead of + "(alternatives: (none found))" if no alternatives were found. + +2008-06-16 Frank Ch. Eigler <fche@elastic.org> + + * elaborate.cxx (session::print_warning): Change to take optional + token as argument. + (*): Adjust callers of print_warning() to pass a token. + (print_token): New function, eliminate recent file name duplication. + (print_error): Use it too. + (semantic_pass_opt2): Tweak way read-only vars' alternatives are + printed. Eliminate relaxation-loop duplicates by printing warnings + only on first iteration. Print alternatives for globals too. + * session.h: Corresponding changes. + +2008-06-16 Stan Cox <scox@redhat.com> + + * elaborate.cxx (semantic_pass_opt2): Only create function + alternatives if needed. Overload compare. + +2008-06-13 Stan Cox <scox@redhat.com> + + * elaborate.cxx (print_warning): Add optional_str parameter. + (semantic_pass_opt2): List variable alternatives for probes and + functions. + * session.h (print_warning): Add optional_str parameter. + +2008-06-13 Josh Stone <joshua.i.stone@intel.com> + + * translate.cxx: Jump out directly after setting last_error, rather + than passively checking last_error everywhere. + * translate.cxx: Only make actionremaining checks at control points, + i.e. roughly at the end of basic blocks, or after executing a few + statements in a row. + +2008-06-13 Frank Ch. Eigler <fche@elastic.org> + + * main.cxx (main): Print generated module name for "-m FOO" + runs also. Stop warning about this implying uncached operation. + +2008-06-12 Stan Cox <scox@redhat.com> + + * elaborate.cxx (print_warning): Make parameter a const. + +2008-06-11 Frank Ch. Eigler <fche@elastic.org> + + * Makefile.am (EXTRA_DIST): Add dwarf_wrappers.h. + +2008-06-11 Mark Wielaard <mwielaard@redhat.com> + + * elaborate.cxx (print_warning): Only output WARNING, don't put it + in the message_str and seen_warnings. + * session.h (print_warning): Reindent. + +2008-06-11 Frank Ch. Eigler <fche@elastic.org> + + * elaborate.cxx (print_warning): Use session.seen_warnings[]. + +2008-06-10 Stan Cox <scox@redhat.com> + + * elaborate.cxx (print_warning): New. + * elaborate.cxx (semantic_pass_opt1): Use it. + +2008-06-11 Tim Moore <timoore@redhat.com> + + * dwarf_wrappers.h (dwfl_assert): Add overload with boolean value + for assertion test. + * dwarf_wrappers.cxx (dwfl_assert): Write boolean condition + version. + * tapsets.cxx (emit_address): Fix up dwfl_asserts that got negated + in changes to dwfl_assert. + + PR 2608 + * dwarf_wrappers.h, dwarf_wrappers.cxx: New files. + * Makefile.in: Regenerated. + * tapsets.cxx (dwarf_assert, dwfl_assert): Move to + dwarf_wrappers.h. + (iterate_over_srcfile_lines, has_single_line_record, + query_srcfile_line): Use dwarf_line_t wrapper. + (die_has_pc): Take a reference to a Dwarf_Die instead of a + pointer. Clean up use of dwfl_assert. + (query_cu): Check that statement raw address matches the beginning + of a statement record. + * elaborate.h: Include iosfwd instead of iostream. + (literal_map_t, resolve_prologue_endings,): New typedef. + + +2008-06-10 Jim Keniston <jkenisto@us.ibm.com> + + * testsuite/systemtap.context/num_args.tcl: Run twice -- + once with dwarf (default) and once with --kelf --ignore-dwarf. + * testsuite/systemtap.context/context.exp: Add num_args to + testlist. :-} + +2008-06-10 David Smith <dsmith@redhat.com> + + * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl): + Initializes .vm_callback. + +2008-06-10 Frank Ch. Eigler <fche@elastic.org> + + PR 6470 + * NEWS: Note argv[] tapset. + * parse.cxx (scan_pp): Better handle premature EOF. + * stapvars.5.in: New file. + * stap.1.in: Mention it. + * Makefile.am (dist_man_MANS): Add stapvars.5. + * configure.ac (AC_CONFIG_FILES): Add stapvars.5.in. + * Makefile.in, configure: Regenerated. + +2008-06-10 Frank Ch. Eigler <fche@elastic.org> + + PR 6470 + * parse.cxx (scan_pp): Eliminate expand_args argument to control + nested preprocess evaluation. Rewrite to use a combination of + exceptions and non-recursion. + (lexer::scan): Ditto. Interpret "$#" as the argc value in all + cases. + * parse.h: Corresponding decl changes. + +2008-06-10 Frank Ch. Eigler <fche@elastic.org> + + PR 6470 + * parse.cxx (eval_comparison): New template function. + (eval_pp_conditional): Call it separately for string/string and + int64/int64 cases. + (lexer::scan): Provide better error message for invalid $NNN. + +2008-06-09 Jim Keniston <jkenisto@us.ibm.com> + + PR 6601 + * tapsets.cxx: For powerpc, reject symbols in .opd + (function descriptor) section. + +2008-06-09 Stan Cox <scox@redhat.com> + + * NEWS: Updated kernel.statement relative line number. + * stapprobes.5.in: Likewise. + +2008-06-09 David Smith <dsmith@redhat.com> + + * tapsets.cxx + (utrace_var_expanding_copy_visitor::visit_target_symbol): Calls + 'syscall_nr' to get the value of '$syscall'. + + * tapsets.cxx (utrace_derived_probe::join_group): Removed + generated inclusion of tracehook.h. + (utrace_var_expanding_copy_visitor::visit_target_symbol): Uses + '_stp_arg(0)' to get value of '$syscall'. + +2008-06-06 Stan Cox <scox@redhat.com> + + * tapsets.cxx (dwflpp::iterate_over_srcfile_lines): + Add parameter line_type_relative. + (enum line_t): New. + (dwarf_query::line_type): New. + (dwarf_query::parse_function_spec): Set line_type. + +2008-06-06 David Smith <dsmith@redhat.com> + + * NEWS: Updated utrace probes descriptions. + * stapprobes.5.in: Ditto. + + * tapsets.cxx (enum utrace_derived_probe_flags): Redefined in + terms of probe types instead of utrace events. + (utrace_var_expanding_copy_visitor::visit_target_symbol): Uses new + utrace_derived_probes_flags values. + (utrace_builder::build): Handles new probe types and new + utrace_derived_probes_flags values. + (utrace_derived_probe_group::emit_probe_decl): Updated to handle + new utrace_derived_probe_flags values. + (utrace_derived_probe_group::emit_module_decls): Ditto. Also + correctly handles 'begin' events correctly by installing a quiesce + handler (instead of running the probe directly). + (register_standard_tapsets): Registers updated utrace probe + types. + +2008-06-05 Srinivasa DS <srinivasa@in.ibm.com> + *configure,configure.ac: -fpie option puts limit on GOT size + and hence systemtap build fails on s390. So use -fPIE which + doesn't put limit on GOT size. + +2008-06-04 Jim Keniston <jkenisto@us.ibm.com> + + * testsuite/systemtap.context/num_args.{stp,tcl}: Added. + Same as args.{stp,tcl}, but refs args using *_arg(). + +2008-06-04 Jim Keniston <jkenisto@us.ibm.com> + + PR 6588 + * tapset/syscalls.stp: Remove return aliases for exit and exit_group. + * testsuite/semok/syscalls_return.stp: Regression test + +2008-06-03 David Smith <dsmith@redhat.com> + + * tapsets.cxx: Added several string tokens that are used instead + of hard-coded strings. + (register_standard_tapsets): Uses new string tokens. + +2008-06-03 Frank Ch. Eigler <fche@elastic.org> + + PR 6429. + * Makefile.am: Don't link stapio with -ldw. + * Makefile.in: Regenerated. + +2008-05-29 Mark Wielaard <mwielaard@redhat.com> + + * Makefile.am (installcheck): Check that make install was run. + * Makefile.in: Regenerated. + +2008-06-02 Frank Ch. Eigler <fche@elastic.org> + + PR6534 + * translate.cxx (c_unparser::emit_module_init): Use UTS_RELEASE + instead of uts_sem/utsname() as kernel version-checking hack. + +2008-06-02 <brolley@redhat.com> + + * stap-client (initialization): port is no longer hard coded. + Initialize avahi_service_tag to _stap._tcp. + (find_and_connect_to_server): Handle server/port returned by + match_server. + (match_server): Obtain server ip address and port from output + of the -r option to avahi-browse. Echo a server/port pair. + +2008-06-02 Zhaolei <zhaolei@cn.fujitsu.com> + + * main.cxx (main): Fix the problem that kernel module compile + failure when runtime directory is set to relative path(stap -R). + +2008-05-30 Dave Brolley <brolley@redhat.com> + + * stap-client, stap-server: New compile server and client scripts. + +2008-05-30 Srinivasa DS <srinivasa@in.ibm.com> + PR 6562 + * tapsets.cxx, translate.cxx: modified one argument for + dwfl_linux_kernel_report_offline(). + * testsuite/systemtap.base/debugpath.exp: Modified testsuite for new + SYSTEMTAP_DEBUGINFO_PATH behaviour. + * stap.1.in: Modified manpage for new SYSTEMTAP_DEBUGINFO_PATH behaviour. + +2008-05-29 Jim Keniston <jkenisto@us.ibm.com> + + PR 6582 + * tapset/context.stp: Added registers_valid(). + * stapfuncs.5.in: Ditto. + * tapset/x86_64/registers.stp: Added registers_valid() check. + * tapset/ppc64/registers.stp: Ditto. + * tapset/i686/registers.stp: Ditto. Also fixed warnings due to + sp_offset and ss_offset not being global. + +2008-05-29 Ananth N Mavinakayanahalli <ananth@in.ibm.com> + + PR 6563 + * tapset/ppc64/registers.stp: Fix powerpc dwarfless argument access + +2008-05-28 Josh Stone <joshua.i.stone@intel.com> + + PR 6529 + * translate.cxx (c_unparser::visit_return_statement): Make sure we + notice errors from evaluating return values. + +2008-05-28 David Smith <dsmith@redhat.com> + + * tapsets.cxx (utrace_derived_probe_group::emit_module_decls): + Removed debug print. + + * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl): + Instead of adding clone handlers, just call the probes directly. + (utrace_derived_probe_group::emit_module_decls): For syscall + probes, on exec detach the parent's utrace engine from the child. + +2008-05-27 Josh Stone <joshua.i.stone@intel.com> + + PR 6432 + * buildrun.cxx (compile_pass): Add the autoconf test for probe_kernel_* + functions, but leave it #if-0'ed for now. + +2008-05-23 Jim Keniston <jkenisto@us.ibm.com> + + PR 4311, cont. Address powerpc dwarfless test failures. + * tapsets.cxx: Convert .funcname to funcname when adding it + to our symbol table. Accept all weak symbols except those + that map to sys_ni_syscall. + +2008-05-23 Srinivasa DS <srinivasa@in.ibm.com> + PR 6429: Inerim fix to avoid compilation error of systemtap module + * runtime/transport/symbols.c: added definitions of struct + module_sect_attr, struct module_sect_attrs for 2.6.25 above kernels. + 2008-05-22 Wenji Huang <wenji.huang@oracle.com> * tapsets.cxx (iterate_over_functions): Fix .statement(NUM) regression. @@ -7,6 +348,12 @@ * tapset/ppc64/registers.stp: Support powerpc register + arg lookup * stapfuncs.5.in: Add powerpc bits; indicate scope of uarg_* access +2008-05-21 David Smith <dsmith@redhat.com> + + * tapsets.cxx (utrace_derived_probe_group::emit_module_decls): + Added new 'event_flag' parameter to task_finder callback. Only + calls probe handlers if we received the correct event. + 2008-05-20 Frank Ch. Eigler <fche@elastic.org> PR 6538 @@ -176,8 +523,6 @@ * systemtap.spec.in: Simplify configuration defaults. -2008-04-29 David Smith <dsmith@redhat.com>:ChangeLog - 2008-04-25 David Smith <dsmith@redhat.com> PR 6455. @@ -56,6 +56,15 @@ the <systemtap@sources.redhat.com> mailing list. Tests that execute probes (pass 5) should include their own .exp/.stp files under any other appropriate systemtap.* testsuite subdirectory. + To run a particular test or set of tests, do: + cd testsuite + make check RUNTESTFLAGS=testname.exp + or + make installcheck RUNTESTFLAGS=testname.exp + To disambiguate among multiple tests with the same name, specify + the directory as well -- for example: + make installcheck RUNTESTFLAGS=systemtap.base/print.exp + - translator Translator changes can easily invalidate tapsets and user script diff --git a/Makefile.am b/Makefile.am index 4eb1335b..3e5bd6c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,12 +10,12 @@ 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 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 +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 stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ - cache.cxx util.cxx coveragedb.cxx + cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ BUILT_SOURCES = @@ -59,6 +59,10 @@ dist-gitversion: git_version.stamp git_version.h: $(srcdir)/git_version.sh -k --srcdir $(srcdir) -o git_version.h +cscope: + cd $(srcdir) && \ + (echo -q ; git ls-files '*.cxx' '*.c' '*.h' | grep -v '^testsuite' ) > cscope.files && \ + cscope -b -q stap_CXXFLAGS = $(AM_CXXFLAGS) @@ -75,9 +79,6 @@ DISTCHECK_CONFIGURE_FLAGS = --with-elfutils=$(elfutils_abs_srcdir) stap_CPPFLAGS += -Iinclude-elfutils stap_LDFLAGS += -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ -Wl,--enable-new-dtags,-rpath,$(pkglibdir) -stapio_CPPFLAGS += -Iinclude-elfutils -stapio_LDFLAGS += -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ - -Wl,--enable-new-dtags,-rpath,$(pkglibdir) BUILT_SOURCES += stamp-elfutils @@ -110,10 +111,10 @@ staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ - runtime/staprun/ctl.c runtime/staprun/unwind_data.c \ + runtime/staprun/ctl.c \ runtime/staprun/relay.c runtime/staprun/relay_old.c stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -stapio_LDADD = @PROCFLAGS@ -ldw -lpthread +stapio_LDADD = @PROCFLAGS@ -lpthread install-exec-hook: if [ `id -u` -eq 0 ]; then chmod 04111 "$(DESTDIR)$(bindir)/staprun"; fi @@ -151,6 +152,7 @@ EXTRA_DIST = buildrun.h elaborate.h loc2c.h session.h \ parse.h staptree.h tapsets.h translate.h \ cache.h hash.h mdfour.h util.h staplog.c coveragedb.h \ testsuite systemtap.spec runtime tapset \ + dwarf_wrappers.h \ git_version.h git_version.sh EXAMPLE_DEST_DIR = $(distdir)/examples @@ -229,6 +231,14 @@ check: $(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)" installcheck: + if test \! -e $(DESTDIR)$(bindir)/stap; then \ + echo $(DESTDIR)$(bindir)/stap doesn\'t exist, run make install; \ + exit -1; \ + fi + if test $(builddir)/stap -nt $(DESTDIR)$(bindir)/stap; then \ + echo "$(DESTDIR)$(bindir)/stap is not recent, run make install"; \ + exit -1; \ + fi $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" rpm: systemtap.spec dist diff --git a/Makefile.in b/Makefile.in index 8ff882b4..675edde2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -37,12 +37,8 @@ bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT) @BUILD_ELFUTILS_TRUE@am__append_2 = -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ @BUILD_ELFUTILS_TRUE@ -Wl,--enable-new-dtags,-rpath,$(pkglibdir) -@BUILD_ELFUTILS_TRUE@am__append_3 = -Iinclude-elfutils -@BUILD_ELFUTILS_TRUE@am__append_4 = -Llib-elfutils -Wl,-rpath-link,lib-elfutils \ -@BUILD_ELFUTILS_TRUE@ -Wl,--enable-new-dtags,-rpath,$(pkglibdir) - -@BUILD_ELFUTILS_TRUE@am__append_5 = stamp-elfutils -@BUILD_ELFUTILS_TRUE@am__append_6 = stamp-elfutils +@BUILD_ELFUTILS_TRUE@am__append_3 = stamp-elfutils +@BUILD_ELFUTILS_TRUE@am__append_4 = stamp-elfutils @BUILD_ELFUTILS_FALSE@stap_DEPENDENCIES = pkglibexec_PROGRAMS = stapio$(EXEEXT) noinst_PROGRAMS = loc2c-test$(EXEEXT) @@ -51,8 +47,8 @@ DIST_COMMON = README $(am__configure_deps) $(dist_man_MANS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/config.in $(srcdir)/stap.1.in $(srcdir)/stapex.5.in \ $(srcdir)/stapfuncs.5.in $(srcdir)/stapprobes.5.in \ - $(srcdir)/staprun.8.in $(srcdir)/systemtap.spec.in \ - $(top_srcdir)/configure \ + $(srcdir)/staprun.8.in $(srcdir)/stapvars.5.in \ + $(srcdir)/systemtap.spec.in $(top_srcdir)/configure \ $(top_srcdir)/man/stapprobes.iosched.5.in \ $(top_srcdir)/man/stapprobes.netdev.5.in \ $(top_srcdir)/man/stapprobes.nfs.5.in \ @@ -76,7 +72,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = systemtap.spec stap.1 stapprobes.5 stapfuncs.5 \ - stapex.5 staprun.8 man/stapprobes.iosched.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 \ @@ -101,14 +97,14 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \ stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \ stap-buildrun.$(OBJEXT) stap-loc2c.$(OBJEXT) \ stap-hash.$(OBJEXT) stap-mdfour.$(OBJEXT) stap-cache.$(OBJEXT) \ - stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT) + stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT) \ + stap-dwarf_wrappers.$(OBJEXT) stap_OBJECTS = $(am_stap_OBJECTS) stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \ $(LDFLAGS) -o $@ am_stapio_OBJECTS = stapio-stapio.$(OBJEXT) stapio-mainloop.$(OBJEXT) \ stapio-common.$(OBJEXT) stapio-ctl.$(OBJEXT) \ - stapio-unwind_data.$(OBJEXT) stapio-relay.$(OBJEXT) \ - stapio-relay_old.$(OBJEXT) + stapio-relay.$(OBJEXT) stapio-relay_old.$(OBJEXT) stapio_OBJECTS = $(am_stapio_OBJECTS) stapio_DEPENDENCIES = stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(stapio_LDFLAGS) \ @@ -176,6 +172,7 @@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ +CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ @@ -274,11 +271,11 @@ pkglibexecdir = ${libexecdir}/${PACKAGE} AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"' 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 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 +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 stap_SOURCES = main.cxx \ parse.cxx staptree.cxx elaborate.cxx translate.cxx \ tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \ - cache.cxx util.cxx coveragedb.cxx + cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ @@ -290,15 +287,15 @@ stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ # of foo-bar.c if it is newer than the foo-bar.o file. Using noinst_foo_SOURCES # instead of foo_SOURCES prevents shipping git_version.h in dist tarballs, # which may cause false GIT_FOO readings. -BUILT_SOURCES = git_version.stamp $(am__append_5) -CLEANFILES = git_version.h $(am__append_6) $(pkglibexec_PROGRAMS) +BUILT_SOURCES = git_version.stamp $(am__append_3) +CLEANFILES = git_version.h $(am__append_4) $(pkglibexec_PROGRAMS) GIT_VERSION_CMD = $(SHELL) $(top_srcdir)/git_version.sh stap_CXXFLAGS = $(AM_CXXFLAGS) stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_1) stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_2) staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ -stapio_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_3) -stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_4) +stapio_CPPFLAGS = $(AM_CPPFLAGS) +stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ # This tells automake's "make distcheck" what we need to compile. @BUILD_ELFUTILS_TRUE@DISTCHECK_CONFIGURE_FLAGS = --with-elfutils=$(elfutils_abs_srcdir) @@ -312,11 +309,11 @@ staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -DSINGLE_THREADED staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ stapio_SOURCES = runtime/staprun/stapio.c \ runtime/staprun/mainloop.c runtime/staprun/common.c \ - runtime/staprun/ctl.c runtime/staprun/unwind_data.c \ + runtime/staprun/ctl.c \ runtime/staprun/relay.c runtime/staprun/relay_old.c stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) -stapio_LDADD = @PROCFLAGS@ -ldw -lpthread +stapio_LDADD = @PROCFLAGS@ -lpthread loc2c_test_SOURCES = loc2c-test.c loc2c.c loc2c_test_CPPFLAGS = $(stap_CPPFLAGS) loc2c_test_LDFLAGS = $(stap_LDFLAGS) @@ -331,6 +328,7 @@ EXTRA_DIST = buildrun.h elaborate.h loc2c.h session.h \ parse.h staptree.h tapsets.h translate.h \ cache.h hash.h mdfour.h util.h staplog.c coveragedb.h \ testsuite systemtap.spec runtime tapset \ + dwarf_wrappers.h \ git_version.h git_version.sh EXAMPLE_DEST_DIR = $(distdir)/examples @@ -410,6 +408,8 @@ stapprobes.5: $(top_builddir)/config.status $(srcdir)/stapprobes.5.in cd $(top_builddir) && $(SHELL) ./config.status $@ stapfuncs.5: $(top_builddir)/config.status $(srcdir)/stapfuncs.5.in cd $(top_builddir) && $(SHELL) ./config.status $@ +stapvars.5: $(top_builddir)/config.status $(srcdir)/stapvars.5.in + cd $(top_builddir) && $(SHELL) ./config.status $@ stapex.5: $(top_builddir)/config.status $(srcdir)/stapex.5.in cd $(top_builddir) && $(SHELL) ./config.status $@ staprun.8: $(top_builddir)/config.status $(srcdir)/staprun.8.in @@ -511,6 +511,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-buildrun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-coveragedb.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-dwarf_wrappers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-elaborate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-loc2c.Po@am__quote@ @@ -527,7 +528,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-relay_old.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-stapio.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-unwind_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-cap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-ctl.Po@am__quote@ @@ -660,20 +660,6 @@ stapio-ctl.obj: runtime/staprun/ctl.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-ctl.obj `if test -f 'runtime/staprun/ctl.c'; then $(CYGPATH_W) 'runtime/staprun/ctl.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/ctl.c'; fi` -stapio-unwind_data.o: runtime/staprun/unwind_data.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-unwind_data.o -MD -MP -MF $(DEPDIR)/stapio-unwind_data.Tpo -c -o stapio-unwind_data.o `test -f 'runtime/staprun/unwind_data.c' || echo '$(srcdir)/'`runtime/staprun/unwind_data.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-unwind_data.Tpo $(DEPDIR)/stapio-unwind_data.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/unwind_data.c' object='stapio-unwind_data.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-unwind_data.o `test -f 'runtime/staprun/unwind_data.c' || echo '$(srcdir)/'`runtime/staprun/unwind_data.c - -stapio-unwind_data.obj: runtime/staprun/unwind_data.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-unwind_data.obj -MD -MP -MF $(DEPDIR)/stapio-unwind_data.Tpo -c -o stapio-unwind_data.obj `if test -f 'runtime/staprun/unwind_data.c'; then $(CYGPATH_W) 'runtime/staprun/unwind_data.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/unwind_data.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-unwind_data.Tpo $(DEPDIR)/stapio-unwind_data.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/unwind_data.c' object='stapio-unwind_data.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-unwind_data.obj `if test -f 'runtime/staprun/unwind_data.c'; then $(CYGPATH_W) 'runtime/staprun/unwind_data.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/unwind_data.c'; fi` - stapio-relay.o: runtime/staprun/relay.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay.o -MD -MP -MF $(DEPDIR)/stapio-relay.Tpo -c -o stapio-relay.o `test -f 'runtime/staprun/relay.c' || echo '$(srcdir)/'`runtime/staprun/relay.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-relay.Tpo $(DEPDIR)/stapio-relay.Po @@ -939,6 +925,20 @@ stap-coveragedb.obj: coveragedb.cxx @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coveragedb.cxx' object='stap-coveragedb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-coveragedb.obj `if test -f 'coveragedb.cxx'; then $(CYGPATH_W) 'coveragedb.cxx'; else $(CYGPATH_W) '$(srcdir)/coveragedb.cxx'; fi` + +stap-dwarf_wrappers.o: dwarf_wrappers.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-dwarf_wrappers.o -MD -MP -MF $(DEPDIR)/stap-dwarf_wrappers.Tpo -c -o stap-dwarf_wrappers.o `test -f 'dwarf_wrappers.cxx' || echo '$(srcdir)/'`dwarf_wrappers.cxx +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-dwarf_wrappers.Tpo $(DEPDIR)/stap-dwarf_wrappers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dwarf_wrappers.cxx' object='stap-dwarf_wrappers.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-dwarf_wrappers.o `test -f 'dwarf_wrappers.cxx' || echo '$(srcdir)/'`dwarf_wrappers.cxx + +stap-dwarf_wrappers.obj: dwarf_wrappers.cxx +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-dwarf_wrappers.obj -MD -MP -MF $(DEPDIR)/stap-dwarf_wrappers.Tpo -c -o stap-dwarf_wrappers.obj `if test -f 'dwarf_wrappers.cxx'; then $(CYGPATH_W) 'dwarf_wrappers.cxx'; else $(CYGPATH_W) '$(srcdir)/dwarf_wrappers.cxx'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-dwarf_wrappers.Tpo $(DEPDIR)/stap-dwarf_wrappers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dwarf_wrappers.cxx' object='stap-dwarf_wrappers.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-dwarf_wrappers.obj `if test -f 'dwarf_wrappers.cxx'; then $(CYGPATH_W) 'dwarf_wrappers.cxx'; else $(CYGPATH_W) '$(srcdir)/dwarf_wrappers.cxx'; fi` install-man1: $(man1_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @@ -1505,6 +1505,11 @@ dist-gitversion: git_version.stamp git_version.h: $(srcdir)/git_version.sh -k --srcdir $(srcdir) -o git_version.h + +cscope: + cd $(srcdir) && \ + (echo -q ; git ls-files '*.cxx' '*.c' '*.h' | grep -v '^testsuite' ) > cscope.files && \ + cscope -b -q @BUILD_ELFUTILS_TRUE@stamp-elfutils: config.status @BUILD_ELFUTILS_TRUE@ $(MAKE) $(AM_MAKEFLAGS) -C build-elfutils all @BUILD_ELFUTILS_TRUE@ for dir in libelf libebl libdw libdwfl backends; do \ @@ -1590,6 +1595,14 @@ check: $(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)" installcheck: + if test \! -e $(DESTDIR)$(bindir)/stap; then \ + echo $(DESTDIR)$(bindir)/stap doesn\'t exist, run make install; \ + exit -1; \ + fi + if test $(builddir)/stap -nt $(DESTDIR)$(bindir)/stap; then \ + echo "$(DESTDIR)$(bindir)/stap is not recent, run make install"; \ + exit -1; \ + fi $(MAKE) -C testsuite installcheck RUNTESTFLAGS="$(RUNTESTFLAGS)" rpm: systemtap.spec dist @@ -1,5 +1,25 @@ * What's new in version 0.7 +- .statement("func@file:*") and .statement("func@file:M-N") probes are now + supported to allow matching a range of lines in a function. This allows + tracing the execution of a function. + +- Scripts relying on probe point wildcards like "syscall.*" that expand + to distinct kprobes are processed significantly faster than before. + +- The vector of script command line arguments is available in a + tapset-provided global array argv[]. It is indexed 1 ... argc, + another global. This can substitute for of preprocessor + directives @NNN that fail at parse time if there are not + enough arguments. + + printf("argv: %s %s %s", argv[1], argv[2], argv[3]) + +- .statement("func@file+line") probes are now supported to allow a + match relative to the entry of the function incremented by line + number. This allows using the same systemtap script if the rest + of the file.c source only changes slightly. + - Stack backtraces for x86 and x86-64 are generated by a dwarf debuginfo-based unwinder based on the code from <jbeulich@novell.com>. This should give more accurate backtraces. @@ -15,12 +35,14 @@ - More user-space probe types are added: - probe process(PID).clone { } - probe process("PATH").clone { } - probe process(PID).exec { } - probe process("PATH").exec { } - probe process(PID).death { } - probe process("PATH").death { } + probe process(PID).begin { } + probe process("PATH").begin { } + probe process(PID).thread.begin { } + probe process("PATH").thread.begin { } + probe process(PID).end { } + probe process("PATH").end { } + probe process(PID).thread.end { } + probe process("PATH").thread.end { } probe process(PID).syscall { } probe process("PATH").syscall { } probe process(PID).syscall.return { } diff --git a/buildrun.cxx b/buildrun.cxx index 76efe7c0..a39f2b63 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -96,6 +96,12 @@ compile_pass (systemtap_session& s) 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; +#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 + * this autoconf. */ + o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-probe-kernel.c, -DSTAPCONF_PROBE_KERNEL,)" << endl; +#endif for (unsigned i=0; i<s.macros.size(); i++) o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl; @@ -1336,6 +1336,7 @@ Optional Features: location). --enable-docs enable building documentation (default on if latex etc. found). + --enable-staticdw support distributions with static libdw Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -6022,8 +6023,8 @@ if test "x$enable_pie" != xno; then save_CFLAGS="$CFLAGS" save_CXXFLAGS="$CXXFLAGS" save_LDFLAGS="$LDFLAGS" - CFLAGS="$CFLAGS -fpie" - CXXFLAGS="$CXXFLAGS -fpie" + CFLAGS="$CFLAGS -fPIE" + CXXFLAGS="$CXXFLAGS -fPIE" LDFLAGS="$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now" cat >conftest.$ac_ext <<_ACEOF void main () {} @@ -6604,9 +6605,17 @@ fi ` +# Check whether --enable-staticdw was given. +if test "${enable_staticdw+set}" = set; then + enableval=$enable_staticdw; +fi + + if test $build_elfutils = no; then # Need libdwfl-capable recent elfutils from Fedora save_LIBS="$LIBS" + if test "x$enable_staticdw" != xyes; then + { echo "$as_me:$LINENO: checking for dwfl_module_getsym in -ldw" >&5 echo $ECHO_N "checking for dwfl_module_getsym in -ldw... $ECHO_C" >&6; } @@ -6678,7 +6687,7 @@ _ACEOF else - { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (dw 0.123+)" >&5 + { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (dw 0.123+)" >&5 echo "$as_me: error: missing elfutils development headers/libraries (dw 0.123+)" >&2;} { (exit 1); exit 1; }; } fi @@ -6754,17 +6763,183 @@ _ACEOF else - { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (ebl 0.123+)" >&5 + { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (ebl 0.123+)" >&5 +echo "$as_me: error: missing elfutils development headers/libraries (ebl 0.123+)" >&2;} + { (exit 1); exit 1; }; } +fi + + + stap_LIBS="$LIBS" + +else + + # Debian ships with a static libdw, which has a circular dependency on libebl + +{ echo "$as_me:$LINENO: checking for dwfl_module_getsym in -ldw" >&5 +echo $ECHO_N "checking for dwfl_module_getsym in -ldw... $ECHO_C" >&6; } +if test "${ac_cv_lib_dw_dwfl_module_getsym+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldw -Wl,--start-group -ldw -lebl -Wl,--end-group -lelf $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dwfl_module_getsym (); +int +main () +{ +return dwfl_module_getsym (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_dw_dwfl_module_getsym=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dw_dwfl_module_getsym=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_dw_dwfl_module_getsym" >&5 +echo "${ECHO_T}$ac_cv_lib_dw_dwfl_module_getsym" >&6; } +if test $ac_cv_lib_dw_dwfl_module_getsym = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDW 1 +_ACEOF + + LIBS="-ldw $LIBS" + +else + + { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (dw 0.123+)" >&5 +echo "$as_me: error: missing elfutils development headers/libraries (dw 0.123+)" >&2;} + { (exit 1); exit 1; }; } +fi + + +{ echo "$as_me:$LINENO: checking for ebl_openbackend in -lebl" >&5 +echo $ECHO_N "checking for ebl_openbackend in -lebl... $ECHO_C" >&6; } +if test "${ac_cv_lib_ebl_ebl_openbackend+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lebl -lelf $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ebl_openbackend (); +int +main () +{ +return ebl_openbackend (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_ebl_ebl_openbackend=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_ebl_ebl_openbackend=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_ebl_ebl_openbackend" >&5 +echo "${ECHO_T}$ac_cv_lib_ebl_ebl_openbackend" >&6; } +if test $ac_cv_lib_ebl_ebl_openbackend = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBEBL 1 +_ACEOF + + LIBS="-lebl $LIBS" + +else + + { { echo "$as_me:$LINENO: error: missing elfutils development headers/libraries (ebl 0.123+)" >&5 echo "$as_me: error: missing elfutils development headers/libraries (ebl 0.123+)" >&2;} { (exit 1); exit 1; }; } fi - stap_LIBS="$LIBS" + stap_LIBS="-Wl,--start-group -ldw -lebl -Wl,--end-group -lelf" + +fi + LIBS="$save_LIBS" else # We built our own and stap_LDFLAGS points at the install. + if test "x$enable_staticdw" != xyes; then stap_LIBS="-ldw -lebl" +else + stap_LIBS="-Wl,--start-group -ldw -lebl -Wl,--end-group -lelf" +fi + fi @@ -7267,7 +7442,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h:config.in" -ac_config_files="$ac_config_files Makefile doc/Makefile systemtap.spec stap.1 stapprobes.5 stapfuncs.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" +ac_config_files="$ac_config_files Makefile doc/Makefile systemtap.spec 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" subdirs="$subdirs testsuite" @@ -7899,6 +8074,7 @@ do "stap.1") CONFIG_FILES="$CONFIG_FILES stap.1" ;; "stapprobes.5") CONFIG_FILES="$CONFIG_FILES stapprobes.5" ;; "stapfuncs.5") CONFIG_FILES="$CONFIG_FILES stapfuncs.5" ;; + "stapvars.5") CONFIG_FILES="$CONFIG_FILES stapvars.5" ;; "stapex.5") CONFIG_FILES="$CONFIG_FILES stapex.5" ;; "staprun.8") CONFIG_FILES="$CONFIG_FILES staprun.8" ;; "man/stapprobes.iosched.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.iosched.5" ;; diff --git a/configure.ac b/configure.ac index b7c1bc47..ed099702 100644 --- a/configure.ac +++ b/configure.ac @@ -87,8 +87,8 @@ AS_IF([test "x$enable_pie" != xno],[ save_CFLAGS="$CFLAGS" save_CXXFLAGS="$CXXFLAGS" save_LDFLAGS="$LDFLAGS" - CFLAGS="$CFLAGS -fpie" - CXXFLAGS="$CXXFLAGS -fpie" + CFLAGS="$CFLAGS -fPIE" + CXXFLAGS="$CXXFLAGS -fPIE" LDFLAGS="$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now" AC_LINK_IFELSE([void main () {}], [ AC_MSG_NOTICE([Compiling with gcc pie et al.]) @@ -180,19 +180,36 @@ AM_CONDITIONAL(BUILD_ELFUTILS, test $build_elfutils = yes) AC_SUBST(elfutils_abs_srcdir, `AS_IF([test $build_elfutils = yes], [cd $with_elfutils && pwd])`) +AC_ARG_ENABLE([staticdw], + [AS_HELP_STRING([--enable-staticdw], [support distributions with static libdw])]) + if test $build_elfutils = no; then # Need libdwfl-capable recent elfutils from Fedora save_LIBS="$LIBS" - AC_CHECK_LIB(dw, dwfl_module_getsym,,[ - AC_MSG_ERROR([missing elfutils development headers/libraries (dw 0.123+)])]) - AC_CHECK_LIB(ebl, ebl_openbackend,,[ - AC_MSG_ERROR([missing elfutils development headers/libraries (ebl 0.123+)])]) + AS_IF([test "x$enable_staticdw" != xyes],[ + AC_CHECK_LIB(dw, dwfl_module_getsym,,[ + AC_MSG_ERROR([missing elfutils development headers/libraries (dw 0.123+)])]) + AC_CHECK_LIB(ebl, ebl_openbackend,,[ + AC_MSG_ERROR([missing elfutils development headers/libraries (ebl 0.123+)])]) + + stap_LIBS="$LIBS" + ],[ + # Debian ships with a static libdw, which has a circular dependency on libebl + AC_CHECK_LIB(dw, dwfl_module_getsym,[],[ + AC_MSG_ERROR([missing elfutils development headers/libraries (dw 0.123+)])], + [-Wl,--start-group -ldw -lebl -Wl,--end-group -lelf]) + dnl XXX Do we need the ebl check, since it was referenced above? + AC_CHECK_LIB(ebl, ebl_openbackend,[],[ + AC_MSG_ERROR([missing elfutils development headers/libraries (ebl 0.123+)])], + [-lelf]) - stap_LIBS="$LIBS" + stap_LIBS="-Wl,--start-group -ldw -lebl -Wl,--end-group -lelf" + ]) LIBS="$save_LIBS" else # We built our own and stap_LDFLAGS points at the install. - stap_LIBS="-ldw -lebl" + AS_IF([test "x$enable_staticdw" != xyes],[stap_LIBS="-ldw -lebl"], + [stap_LIBS="-Wl,--start-group -ldw -lebl -Wl,--end-group -lelf"]) fi AC_SUBST(stap_LIBS) @@ -233,7 +250,7 @@ AC_CHECK_HEADERS([tr1/unordered_map]) AC_LANG_POP(C++) AC_CONFIG_HEADERS([config.h:config.in]) -AC_CONFIG_FILES(Makefile doc/Makefile systemtap.spec stap.1 stapprobes.5 stapfuncs.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) +AC_CONFIG_FILES(Makefile doc/Makefile systemtap.spec 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) AC_CONFIG_SUBDIRS(testsuite) AC_OUTPUT diff --git a/cscope.files b/cscope.files deleted file mode 100644 index d2d0e462..00000000 --- a/cscope.files +++ /dev/null @@ -1,181 +0,0 @@ --q -./buildrun.cxx -./buildrun.h -./cache.cxx -./cache.h -./config.h -./coveragedb.cxx -./coveragedb.h -./elaborate.cxx -./elaborate.h -./git_version.h -./hash.cxx -./hash.h -./loc2c.c -./loc2c.h -./loc2c-test.c -./main.cxx -./mdfour.c -./mdfour.h -./parse.cxx -./parse.h -./runtime/alloc.c -./runtime/arith.c -./runtime/autoconf-constant-tsc.c -./runtime/autoconf-hrtimer-rel.c -./runtime/autoconf-inode-private.c -./runtime/autoconf-ktime-get-real.c -./runtime/autoconf-module-nsections.c -./runtime/autoconf-nameidata.c -./runtime/autoconf-tsc-khz.c -./runtime/autoconf-unregister-kprobes.c -./runtime/autoconf-x86-uniregs.c -./runtime/bench2/itest.c -./runtime/copy.c -./runtime/counter.c -./runtime/debug.h -./runtime/docs/examples/argv.c -./runtime/docs/examples/foreach.c -./runtime/docs/examples/list.c -./runtime/docs/examples/map.c -./runtime/docs/examples/template.c -./runtime/io.c -./runtime/loc2c-runtime.h -./runtime/map.c -./runtime/map-gen.c -./runtime/map.h -./runtime/map-stat.c -./runtime/mempool.c -./runtime/perf.c -./runtime/perf.h -./runtime/pmap-gen.c -./runtime/print.c -./runtime/print_new.c -./runtime/print_old.c -./runtime/probes/agg/count1.c -./runtime/probes/agg/count2.c -./runtime/probes/agg/stat1.c -./runtime/probes/bench/bench.c -./runtime/probes/bench/bench_io1.c -./runtime/probes/bench/bench_io2.c -./runtime/probes/bench/bench_io3.c -./runtime/probes/bench/bench_io4.c -./runtime/probes/bench/bench_multi.c -./runtime/probes/bench/bench_ret.c -./runtime/probes/bench/itest.c -./runtime/probes/bench/ttest.c -./runtime/probes.c -./runtime/probes/os_timer/os_timer.c -./runtime/probes/scf/scf.c -./runtime/probes/shellsnoop/shellsnoop.c -./runtime/probes/tasklet/stp_tasklet.c -./runtime/probes/test4/test4.c -./runtime/probes/where_func/kprobe_where_funct.c -./runtime/procfs.c -./runtime/regs.c -./runtime/regs.h -./runtime/regs-ia64.c -./runtime/runtime.h -./runtime/stack-arm.c -./runtime/stack.c -./runtime/stack-i386.c -./runtime/stack-ia64.c -./runtime/stack-ppc64.c -./runtime/stack-s390.c -./runtime/stack-x86_64.c -./runtime/staprun/cap.c -./runtime/staprun/common.c -./runtime/staprun/ctl.c -./runtime/staprun/mainloop.c -./runtime/staprun/relay.c -./runtime/staprun/relay_old.c -./runtime/staprun/stapio.c -./runtime/staprun/stap_merge.c -./runtime/staprun/staprun.c -./runtime/staprun/staprun_funcs.c -./runtime/staprun/staprun.h -./runtime/staprun/symbols.c -./runtime/staprun/unwind_data.c -./runtime/stat.c -./runtime/stat-common.c -./runtime/stat.h -./runtime/string.c -./runtime/string.h -./runtime/sym.c -./runtime/sym.h -./runtime/task_finder.c -./runtime/tests/agg/count.c -./runtime/tests/agg/stats.c -./runtime/tests/maps/ii.c -./runtime/tests/maps/iiiiii.c -./runtime/tests/maps/iiss.c -./runtime/tests/maps/is.c -./runtime/tests/maps/issii.c -./runtime/tests/maps/isx.c -./runtime/tests/maps/map_format.c -./runtime/tests/maps/setadd.c -./runtime/tests/maps/si.c -./runtime/tests/maps/size.c -./runtime/tests/maps/sort2.c -./runtime/tests/maps/sort.c -./runtime/tests/maps/sort_stat.c -./runtime/tests/maps/ssssss.c -./runtime/tests/math/div64.c -./runtime/tests/pmaps/ii2.c -./runtime/tests/pmaps/ii3.c -./runtime/tests/pmaps/ii.c -./runtime/tests/pmaps/is.c -./runtime/tests/pmaps/ix2.c -./runtime/tests/pmaps/ix.c -./runtime/tests/pmaps/ix_log.c -./runtime/tests/pmaps/ix_none.c -./runtime/tests/pmaps/map_format.c -./runtime/tests/pmaps/si.c -./runtime/tests/pmaps/size.c -./runtime/tests/string/print_cstr.c -./runtime/tests/string/printf_A.c -./runtime/tests/string/printf_B.c -./runtime/tests/string/string1.c -./runtime/tests/string/string2.c -./runtime/tests/string/string3.c -./runtime/time.c -./runtime/transport/control.c -./runtime/transport/procfs.c -./runtime/transport/relayfs.c -./runtime/transport/relayfs.h -./runtime/transport/symbols.c -./runtime/transport/transport.c -./runtime/transport/transport.h -./runtime/transport/transport_msgs.h -./runtime/transport/utt.c -./runtime/transport/utt.h -./runtime/unwind.c -./runtime/unwind/i386.h -./runtime/unwind/unwind.h -./runtime/unwind/x86_64.h -./runtime/uprobes/uprobes_arch.c -./runtime/uprobes/uprobes_arch.h -./runtime/uprobes/uprobes.c -./runtime/uprobes/uprobes.h -./runtime/uprobes/uprobes_i386.c -./runtime/uprobes/uprobes_i386.h -./runtime/uprobes/uprobes_ppc64.c -./runtime/uprobes/uprobes_ppc64.h -./runtime/uprobes/uprobes_s390.c -./runtime/uprobes/uprobes_s390.h -./runtime/uprobes/uprobes_x86_64.c -./runtime/uprobes/uprobes_x86_64.h -./runtime/uprobes/uprobes_x86.c -./runtime/uprobes/uprobes_x86.h -./runtime/vsprintf.c -./session.h -./staplog.c -./staptree.cxx -./staptree.h -./tapsets.cxx -./tapsets.h -./tapset/test/master.c -./translate.cxx -./translate.h -./util.cxx -./util.h diff --git a/doc/Makefile.in b/doc/Makefile.in index a2700d3c..a31d76f0 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -55,6 +55,7 @@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ +CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ diff --git a/doc/langref.tex b/doc/langref.tex index 46d350f6..e2c630d4 100644 --- a/doc/langref.tex +++ b/doc/langref.tex @@ -751,7 +751,13 @@ In most cases, the path should be relative to the top of the linux source directory, although an absolute path may be necessary for some kernels. If a relative pathname doesn't work, try absolute. \item The third part is optional if the file name part was given. It identifies -the line number in the source file, preceded by a colon. +the line number in the source file, preceded by a ``:'' or ``+''. +The line number is assumed to be an +absolute line number if preceded by a ``:'', or relative to the entry of +the function if preceded by a ``+''. +All the lines in the function can be matched with ``:*''. +A range of lines x through y can be matched with ``:x-y''. + \end{enumerate} Alternately, specify PATTERN as a numeric constant to indicate a relative module address or an absolute kernel address. @@ -825,6 +831,8 @@ Example: # Refers to the statement at line 2917 within the # kernel/sched.c file: kernel.statement("*@kernel/sched.c:2917") +# Refers to the statement at line bio_init+3 within the fs/bio.c file: +kernel.statement("bio_init@fs/bio.c+3") \end{verbatim} \end{vindent} diff --git a/dwarf_wrappers.cxx b/dwarf_wrappers.cxx new file mode 100644 index 00000000..93cb36a2 --- /dev/null +++ b/dwarf_wrappers.cxx @@ -0,0 +1,46 @@ +// -*- C++ -*- +// 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. + +#include "dwarf_wrappers.h" +#include "staptree.h" + +#include <cstring> +#include <string> +#include <elfutils/libdwfl.h> + +using std::string; + +void dwfl_assert(const string& desc, int rc) +{ + if (rc == 0) + return; + string msg = "libdwfl failure (" + desc + "): "; + if (rc < 0) + msg += dwfl_errmsg (rc); + else + msg += std::strerror (rc); + throw semantic_error (msg); +} + +void dwarf_assert(const string& desc, int rc) +{ + if (rc == 0) + return; + string msg = "libdw failure (" + desc + "): "; + if (rc < 0) + msg += dwarf_errmsg (rc); + else + msg += std::strerror (rc); + throw semantic_error (msg); +} + +void dwfl_assert(const std::string& desc, bool condition) +{ + if (!condition) + dwarf_assert(desc, -1); +} diff --git a/dwarf_wrappers.h b/dwarf_wrappers.h new file mode 100644 index 00000000..c498de05 --- /dev/null +++ b/dwarf_wrappers.h @@ -0,0 +1,93 @@ +// -*- C++ -*- +// 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. + +#ifndef DWARF_WRAPPERS_H +#define DWARF_WRAPPERS_H 1 +#include <elfutils/libdw.h> + +#include <string> + +// NB: "rc == 0" means OK in this case +void dwfl_assert(const std::string& desc, int rc); + +// Throw error if pointer is NULL. +template <typename T> +void dwfl_assert(const std::string& desc, T* ptr) +{ + if (!ptr) + dwfl_assert(desc, -1); +} + +// Throw error if pointer is NULL +template <typename T> +void dwfl_assert(const std::string& desc, const T* ptr) +{ + if (!ptr) + dwfl_assert(desc, -1); +} + +// Throw error if condition is false +void dwfl_assert(const std::string& desc, bool condition); + +// NB: "rc == 0" means OK in this case +void dwarf_assert(const std::string& desc, int rc); + +// Throw error if pointer is NULL +template <typename T> +void dwarf_assert(const std::string& desc, T* ptr) +{ + if (!ptr) + dwarf_assert(desc, -1); +} + + +class dwarf_line_t +{ +public: + const Dwarf_Line* line; + dwarf_line_t() : line(0) {} + dwarf_line_t(const Dwarf_Line* line_) : line(line_) {} + + dwarf_line_t& operator= (const Dwarf_Line* line_) + { + line = (line_); + return *this; + } + + operator bool() const + { + return line != 0; + } + + int lineno() const + { + int lineval; + if (!line) + dwarf_assert("dwarf_line_t::lineno", -1); + dwarf_lineno(const_cast<Dwarf_Line*>(line), &lineval); + return lineval; + } + Dwarf_Addr addr() const + { + Dwarf_Addr addrval; + if (!line) + dwarf_assert("dwarf_line_t::addr", -1); + dwarf_lineaddr(const_cast<Dwarf_Line*>(line), &addrval); + return addrval; + } + const char* linesrc(Dwarf_Word* mtime = 0, Dwarf_Word* length = 0) + { + const char* retval = dwarf_linesrc(const_cast<Dwarf_Line*>(line), mtime, + length); + dwarf_assert("dwarf_line_t::linesrc", retval); + return retval; + } +}; + + +#endif diff --git a/elaborate.cxx b/elaborate.cxx index 2f246e2c..73358a1d 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1,5 +1,6 @@ // elaboration functions // Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2008 Intel Corporation // // 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 @@ -322,7 +323,7 @@ match_node::find_and_build (systemtap_session& s, throw semantic_error (string("probe point truncated at position ") + lex_cast<string> (pos) + - " (follow:" + alternatives + ")"); + " (follow:" + alternatives + ")", loc->tok); } map<string, literal *> param_map; @@ -394,7 +395,8 @@ match_node::find_and_build (systemtap_session& s, throw semantic_error(string("probe point mismatch at position ") + lex_cast<string> (pos) + - " (alternatives:" + alternatives + ")"); + " (alternatives:" + alternatives + ")", + loc->tok); } } else @@ -409,7 +411,8 @@ match_node::find_and_build (systemtap_session& s, throw semantic_error (string("probe point mismatch at position ") + lex_cast<string> (pos) + - " (alternatives:" + alternatives + ")"); + " (alternatives:" + alternatives + ")", + loc->tok); } match_node* subnode = i->second; @@ -1194,11 +1197,40 @@ systemtap_session::systemtap_session (): op (0), up (0), sym_kprobes_text_start (0), sym_kprobes_text_end (0), - sym_stext (0) + sym_stext (0), + module_cache (0), + last_token (0) { } +// Print this given token, but abbreviate it if the last one had the +// same file name. +void +systemtap_session::print_token (ostream& o, const token* tok) +{ + assert (tok); + + if (last_token && last_token->location.file == tok->location.file) + { + stringstream tmpo; + tmpo << *tok; + string ts = tmpo.str(); + // search & replace the file name with nothing + size_t idx = ts.find (tok->location.file); + if (idx != string::npos) + ts.replace (idx, tok->location.file.size(), ""); + + o << ts; + } + else + o << *tok; + + last_token = tok; +} + + + void systemtap_session::print_error (const semantic_error& e) { @@ -1211,9 +1243,9 @@ systemtap_session::print_error (const semantic_error& e) message << "semantic error: " << e.what (); if (e.tok1 || e.tok2) message << ": "; - if (e.tok1) message << *e.tok1; + if (e.tok1) print_token (message, e.tok1); message << e.msg2; - if (e.tok2) message << *e.tok2; + if (e.tok2) print_token (message, e.tok2); message << endl; message_str = message.str(); @@ -1228,6 +1260,19 @@ systemtap_session::print_error (const semantic_error& e) print_error (* e.chain); } +void +systemtap_session::print_warning (const string& message_str, const token* tok) +{ + // Duplicate elimination + if (seen_warnings.find (message_str) == seen_warnings.end()) + { + seen_warnings.insert (message_str); + clog << "WARNING: " << message_str; + if (tok) { clog << ": "; print_token (clog, tok); } + clog << endl; + } +} + // ------------------------------------------------------------------------ // semantic processing: symbol resolution @@ -1558,7 +1603,7 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) { if (s.functions[i]->tok->location.file == s.user_file->name && // !tapset ! s.suppress_warnings) - clog << "WARNING: eliding unused function " << *s.functions[i]->tok << endl; + s.print_warning ("eliding unused function '" + s.functions[i]->name + "'", s.functions[i]->tok); else if (s.verbose>2) clog << "Eliding unused function " << s.functions[i]->name << endl; @@ -1579,10 +1624,10 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p) // Do away with local & global variables that are never // written nor read. -void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) +void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations) { varuse_collecting_visitor vut; - + for (unsigned i=0; i<s.probes.size(); i++) { s.probes[i]->body->visit (& vut); @@ -1601,7 +1646,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) // Now in vut.read/written, we have a mixture of all locals, globals - for (unsigned i=0; i<s.probes.size(); i++) + for (unsigned i=0; i<s.probes.size(); i++) for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */) { vardecl* l = s.probes[i]->locals[j]; @@ -1611,7 +1656,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) { if (l->tok->location.file == s.user_file->name && // !tapset ! s.suppress_warnings) - clog << "WARNING: eliding unused variable " << *l->tok << endl; + s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) clog << "Eliding unused local variable " << l->name << " in " << s.probes[i]->name << endl; @@ -1626,12 +1671,24 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) else { if (vut.written.find (l) == vut.written.end()) - if (! s.suppress_warnings) - clog << "WARNING: read-only local variable " << *l->tok << endl; - + if (iterations == 0 && ! s.suppress_warnings) + { + stringstream o; + vector<vardecl*>::iterator it; + for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + for (it = s.globals.begin(); it != s.globals.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + + s.print_warning ("read-only local variable '" + l->name + "' " + + (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok); + } j++; } } + for (unsigned i=0; i<s.functions.size(); i++) for (unsigned j=0; j<s.functions[i]->locals.size(); /* see below */) { @@ -1641,7 +1698,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) { if (l->tok->location.file == s.user_file->name && // !tapset ! s.suppress_warnings) - clog << "WARNING: eliding unused variable " << *l->tok << endl; + s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) clog << "Eliding unused local variable " << l->name << " in function " << s.functions[i]->name @@ -1657,8 +1714,25 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) else { if (vut.written.find (l) == vut.written.end()) - if (! s.suppress_warnings) - clog << "WARNING: read-only local variable " << *l->tok << endl; + if (iterations == 0 && ! s.suppress_warnings) + { + stringstream o; + vector<vardecl*>::iterator it; + for ( it = s.functions[i]->formal_args.begin() ; + it != s.functions[i]->formal_args.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + for (it = s.functions[i]->locals.begin(); it != s.functions[i]->locals.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + for (it = s.globals.begin(); it != s.globals.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + + s.print_warning ("read-only local variable '" + l->name + "' " + + (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok); + } + j++; } } @@ -1670,7 +1744,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) { if (l->tok->location.file == s.user_file->name && // !tapset ! s.suppress_warnings) - clog << "WARNING: eliding unused variable " << *l->tok << endl; + s.print_warning ("eliding unused variable '" + l->name + "'", l->tok); else if (s.verbose>2) clog << "Eliding unused global variable " << l->name << endl; @@ -1683,10 +1757,19 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p) } else { - if (vut.written.find (l) == vut.written.end() && - ! l->init) // no initializer - if (! s.suppress_warnings) - clog << "WARNING: read-only global variable " << *l->tok << endl; + if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer + if (iterations == 0 && ! s.suppress_warnings) + { + stringstream o; + vector<vardecl*>::iterator it; + for (it = s.globals.begin(); it != s.globals.end(); it++) + if (l->name != (*it)->name) + o << " " << (*it)->name; + + s.print_warning ("read-only global variable '" + l->name + "' " + + (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok); + } + i++; } } @@ -1912,7 +1995,20 @@ dead_stmtexpr_remover::visit_block (block *s) current_stmt = & s->statements[i]; s->statements[i]->visit (this); if (*current_stmt != 0) - new_stmts.push_back (*current_stmt); + { + // flatten nested blocks into this one + block *b = dynamic_cast<block *>(*current_stmt); + if (b) + { + if (session.verbose>2) + clog << "Flattening nested block " << *b->tok << endl; + new_stmts.insert(new_stmts.end(), + b->statements.begin(), b->statements.end()); + relaxed_p = false; + } + else + new_stmts.push_back (*current_stmt); + } current_stmt = last_stmt; } if (new_stmts.size() == 0) @@ -1948,27 +2044,49 @@ dead_stmtexpr_remover::visit_if_statement (if_statement *s) } current_stmt = last_stmt; - if (s->elseblock == 0 && s->thenblock == 0) + if (s->thenblock == 0) { - // We may be able to elide this statement, if the condition - // expression is side-effect-free. - varuse_collecting_visitor vct; - s->condition->visit(& vct); - if (vct.side_effect_free ()) + if (s->elseblock == 0) + { + // We may be able to elide this statement, if the condition + // expression is side-effect-free. + varuse_collecting_visitor vct; + s->condition->visit(& vct); + if (vct.side_effect_free ()) + { + if (session.verbose>2) + clog << "Eliding side-effect-free if statement " + << *s->tok << endl; + *current_stmt = 0; // yeah, baby + } + else + { + // We can still turn it into a simple expr_statement though... + if (session.verbose>2) + clog << "Creating simple evaluation from if statement " + << *s->tok << endl; + expr_statement *es = new expr_statement; + es->value = s->condition; + es->tok = es->value->tok; + *current_stmt = es; + } + } + else { + // For an else without a then, we can invert the condition logic to + // avoid having a null statement in the thenblock if (session.verbose>2) - clog << "Eliding side-effect-free if statement " << *s->tok << endl; - *current_stmt = 0; // yeah, baby - return; + clog << "Inverting the condition of if statement " + << *s->tok << endl; + unary_expression *ue = new unary_expression; + ue->operand = s->condition; + ue->tok = ue->operand->tok; + ue->op = "!"; + s->condition = ue; + s->thenblock = s->elseblock; + s->elseblock = 0; } } - - if (s->thenblock == 0) - { - // Can't elide this whole if/else statement; put a null in there. - s->thenblock = new null_statement(); - s->thenblock->tok = s->tok; - } } void @@ -2084,8 +2202,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) if (p->body == 0) { if (! s.suppress_warnings) - clog << "WARNING: side-effect-free probe '" << p->name << "' " - << *p->tok << endl; + s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok); p->body = new null_statement(); p->body->tok = p->tok; @@ -2109,8 +2226,7 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) if (fn->body == 0) { if (! s.suppress_warnings) - clog << "WARNING: side-effect-free function '" << fn->name << "' " - << *fn->tok << endl; + s.print_warning ("side-effect-free function '" + fn->name + "'", fn->tok); fn->body = new null_statement(); fn->body->tok = fn->tok; @@ -2124,6 +2240,362 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) } } + +// ------------------------------------------------------------------------ + +// The goal of this visitor is to reduce top-level expressions in void context +// into separate statements that evaluate each subcomponent of the expression. +// The dead-statement-remover can later remove some parts if they have no side +// effects. +struct void_statement_reducer: public traversing_visitor +{ + systemtap_session& session; + bool& relaxed_p; + statement** current_stmt; // pointer to current stmt* being iterated + expr_statement* current_expr; // pointer to current expr being iterated + set<vardecl*> focal_vars; // vars considered subject to side-effects + + void_statement_reducer(systemtap_session& s, bool& r): + session(s), relaxed_p(r), current_stmt(0), current_expr(0) {} + + // these just maintain current_stmt while recursing, but don't visit + // expressions in the conditional / loop controls. + void visit_expr_statement (expr_statement* s); + void visit_block (block *s); + void visit_if_statement (if_statement* s); + void visit_for_loop (for_loop* s); + void visit_foreach_loop (foreach_loop* s); + + // these expressions get rewritten into their statement equivalents + void visit_logical_or_expr (logical_or_expr* e); + void visit_logical_and_expr (logical_and_expr* e); + void visit_ternary_expression (ternary_expression* e); + + // all of these can be reduced into simpler statements + void visit_binary_expression (binary_expression* e); + void visit_unary_expression (unary_expression* e); + void visit_comparison (comparison* e); + void visit_concatenation (concatenation* e); + void visit_functioncall (functioncall* e); + void visit_print_format (print_format* e); + + // these are a bit hairy to grok due to the intricacies of indexables and + // stats, so I'm chickening out and skipping them... + void visit_array_in (array_in* e) {} + void visit_arrayindex (arrayindex* e) {} + void visit_stat_op (stat_op* e) {} + void visit_hist_op (hist_op* e) {} + + // these can't be reduced because they always have an effect + void visit_return_statement (return_statement* s) {} + void visit_delete_statement (delete_statement* s) {} + void visit_pre_crement (pre_crement* e) {} + void visit_post_crement (post_crement* e) {} + void visit_assignment (assignment* e) {} +}; + + +void +void_statement_reducer::visit_expr_statement (expr_statement* s) +{ + assert(!current_expr); // it shouldn't be possible to have nested expr's + current_expr = s; + s->value->visit (this); + current_expr = NULL; +} + +void +void_statement_reducer::visit_block (block *s) +{ + statement** last_stmt = current_stmt; + for (unsigned i=0; i<s->statements.size(); i++ ) + { + current_stmt = & s->statements[i]; + s->statements[i]->visit (this); + } + current_stmt = last_stmt; +} + +void +void_statement_reducer::visit_if_statement (if_statement* s) +{ + statement** last_stmt = current_stmt; + current_stmt = & s->thenblock; + s->thenblock->visit (this); + + if (s->elseblock) + { + current_stmt = & s->elseblock; + s->elseblock->visit (this); + } + current_stmt = last_stmt; +} + +void +void_statement_reducer::visit_for_loop (for_loop* s) +{ + statement** last_stmt = current_stmt; + current_stmt = & s->block; + s->block->visit (this); + current_stmt = last_stmt; +} + +void +void_statement_reducer::visit_foreach_loop (foreach_loop* s) +{ + statement** last_stmt = current_stmt; + current_stmt = & s->block; + s->block->visit (this); + current_stmt = last_stmt; +} + +void +void_statement_reducer::visit_logical_or_expr (logical_or_expr* e) +{ + // In void context, the evaluation of "a || b" is exactly like + // "if (!a) b", so let's do that instead. + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Creating if statement from unused logical-or " + << *e->tok << endl; + + if_statement *is = new if_statement; + is->tok = e->tok; + is->elseblock = 0; + *current_stmt = is; + current_expr = NULL; + + unary_expression *ue = new unary_expression; + ue->operand = e->left; + ue->tok = e->tok; + ue->op = "!"; + is->condition = ue; + + expr_statement *es = new expr_statement; + es->value = e->right; + es->tok = es->value->tok; + is->thenblock = es; + + is->visit(this); + relaxed_p = false; +} + +void +void_statement_reducer::visit_logical_and_expr (logical_and_expr* e) +{ + // In void context, the evaluation of "a && b" is exactly like + // "if (a) b", so let's do that instead. + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Creating if statement from unused logical-and " + << *e->tok << endl; + + if_statement *is = new if_statement; + is->tok = e->tok; + is->elseblock = 0; + is->condition = e->left; + *current_stmt = is; + current_expr = NULL; + + expr_statement *es = new expr_statement; + es->value = e->right; + es->tok = es->value->tok; + is->thenblock = es; + + is->visit(this); + relaxed_p = false; +} + +void +void_statement_reducer::visit_ternary_expression (ternary_expression* e) +{ + // In void context, the evaluation of "a ? b : c" is exactly like + // "if (a) b else c", so let's do that instead. + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Creating if statement from unused ternary expression " + << *e->tok << endl; + + if_statement *is = new if_statement; + is->tok = e->tok; + is->condition = e->cond; + *current_stmt = is; + current_expr = NULL; + + expr_statement *es = new expr_statement; + es->value = e->truevalue; + es->tok = es->value->tok; + is->thenblock = es; + + es = new expr_statement; + es->value = e->falsevalue; + es->tok = es->value->tok; + is->elseblock = es; + + is->visit(this); + relaxed_p = false; +} + +void +void_statement_reducer::visit_binary_expression (binary_expression* e) +{ + // When the result of a binary operation isn't needed, it's just as good to + // evaluate the operands as sequential statements in a block. + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Eliding unused binary " << *e->tok << endl; + + block *b = new block; + b->tok = current_expr->tok; + *current_stmt = b; + current_expr = NULL; + + expr_statement *es = new expr_statement; + es->value = e->left; + es->tok = es->value->tok; + b->statements.push_back(es); + + es = new expr_statement; + es->value = e->right; + es->tok = es->value->tok; + b->statements.push_back(es); + + b->visit(this); + relaxed_p = false; +} + +void +void_statement_reducer::visit_unary_expression (unary_expression* e) +{ + // When the result of a unary operation isn't needed, it's just as good to + // evaluate the operand directly + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Eliding unused unary " << *e->tok << endl; + + current_expr->value = e->operand; + current_expr->tok = current_expr->value->tok; + current_expr->value->visit(this); + + relaxed_p = false; +} + +void +void_statement_reducer::visit_comparison (comparison* e) +{ + visit_binary_expression(e); +} + +void +void_statement_reducer::visit_concatenation (concatenation* e) +{ + visit_binary_expression(e); +} + +void +void_statement_reducer::visit_functioncall (functioncall* e) +{ + // If a function call is pure and its result ignored, we can elide the call + // and just evaluate the arguments in sequence + + if (!e->args.size()) + return; + + varuse_collecting_visitor vut; + vut.traversed.insert (e->referent); + vut.current_function = e->referent; + e->referent->body->visit (& vut); + if (!vut.side_effect_free_wrt (focal_vars)) + return; + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Eliding side-effect-free function call " << *e->tok << endl; + + block *b = new block; + b->tok = e->tok; + *current_stmt = b; + current_expr = NULL; + + for (unsigned i=0; i<e->args.size(); i++ ) + { + expr_statement *es = new expr_statement; + es->value = e->args[i]; + es->tok = es->value->tok; + b->statements.push_back(es); + } + + b->visit(this); + relaxed_p = false; +} + +void +void_statement_reducer::visit_print_format (print_format* e) +{ + // When an sprint's return value is ignored, we can simply evaluate the + // arguments in sequence + + if (e->print_to_stream || !e->args.size()) + return; + + assert(current_expr && current_expr->value == e); + + if (session.verbose>2) + clog << "Eliding unused print " << *e->tok << endl; + + block *b = new block; + b->tok = e->tok; + *current_stmt = b; + current_expr = NULL; + + for (unsigned i=0; i<e->args.size(); i++ ) + { + expr_statement *es = new expr_statement; + es->value = e->args[i]; + es->tok = es->value->tok; + b->statements.push_back(es); + } + + b->visit(this); + relaxed_p = false; +} + + +void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) +{ + // Let's simplify statements with unused computed values. + + void_statement_reducer vuv (s, relaxed_p); + // This instance may be reused for multiple probe/function body trims. + + vuv.focal_vars.insert (s.globals.begin(), s.globals.end()); + + for (unsigned i=0; i<s.probes.size(); i++) + { + derived_probe* p = s.probes[i]; + vuv.current_stmt = & p->body; + p->body->visit (& vuv); + } + for (unsigned i=0; i<s.functions.size(); i++) + { + functiondecl* fn = s.functions[i]; + vuv.current_stmt = & fn->body; + fn->body->visit (& vuv); + } +} + + struct duplicate_function_remover: public functioncall_traversing_visitor { systemtap_session& s; @@ -2176,7 +2648,7 @@ get_functionsig (functiondecl* f) return str; } -void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) +void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p) { // Walk through all the functions, looking for duplicates. map<string, functiondecl*> functionsig_map; @@ -2232,6 +2704,7 @@ semantic_pass_optimize1 (systemtap_session& s) int rc = 0; bool relaxed_p = false; + unsigned iterations = 0; while (! relaxed_p) { if (pending_interrupts) break; @@ -2239,9 +2712,12 @@ semantic_pass_optimize1 (systemtap_session& s) relaxed_p = true; // until proven otherwise semantic_pass_opt1 (s, relaxed_p); - semantic_pass_opt2 (s, relaxed_p); + semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0 semantic_pass_opt3 (s, relaxed_p); semantic_pass_opt4 (s, relaxed_p); + semantic_pass_opt5 (s, relaxed_p); + + iterations ++; } return rc; @@ -2263,7 +2739,7 @@ semantic_pass_optimize2 (systemtap_session& s) if (pending_interrupts) break; relaxed_p = true; // until proven otherwise - semantic_pass_opt5 (s, relaxed_p); + semantic_pass_opt6 (s, relaxed_p); } return rc; diff --git a/elaborate.h b/elaborate.h index 30bf5bce..c0e35477 100644 --- a/elaborate.h +++ b/elaborate.h @@ -13,7 +13,8 @@ #include "parse.h" #include <string> #include <vector> -#include <iostream> +//#include <iostream> +#include <iosfwd> #include <sstream> #include <map> @@ -175,21 +176,23 @@ struct derived_probe_group // ------------------------------------------------------------------------ +typedef std::map<std::string, literal*> literal_map_t; + struct derived_probe_builder { virtual void build(systemtap_session & sess, probe* base, probe_point* location, - std::map<std::string, literal*> const & parameters, + literal_map_t const & parameters, std::vector<derived_probe*> & finished_results) = 0; virtual ~derived_probe_builder() {} virtual void build_no_more (systemtap_session &) {} - static bool has_null_param (std::map<std::string, literal*> const & parameters, + static bool has_null_param (literal_map_t const & parameters, const std::string& key); - static bool get_param (std::map<std::string, literal*> const & parameters, + static bool get_param (literal_map_t const & parameters, const std::string& key, std::string& value); - static bool get_param (std::map<std::string, literal*> const & parameters, + static bool get_param (literal_map_t const & parameters, const std::string& key, int64_t& value); }; @@ -26,6 +26,7 @@ #include <sstream> #include <cerrno> #include <cstdlib> +#include <limits.h> extern "C" { #include <glob.h> @@ -513,7 +514,6 @@ main (int argc, char * const argv []) } } - cerr << "Warning: using '-m' disables cache support." << endl; s.use_cache = false; break; @@ -677,6 +677,16 @@ main (int argc, char * const argv []) usage(s, 1); } + // translate path of runtime to absolute path + if (s.runtime_path[0] != '/') + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) + { + s.runtime_path = string(cwd) + "/" + s.runtime_path; + } + } + int rc = 0; // override PATH and LC_ALL @@ -976,7 +986,10 @@ main (int argc, char * const argv []) rc = compile_pass (s); if (rc == 0 && s.last_pass == 4) - cout << s.hash_path << endl; + { + cout << ((s.hash_path == "") ? (s.module_name + string(".ko")) : s.hash_path); + cout << endl; + } times (& tms_after); gettimeofday (&tv_after, NULL); @@ -150,6 +150,27 @@ parser::last () } + +template <typename OPERAND> +bool eval_comparison (const OPERAND& lhs, const token* op, const OPERAND& rhs) +{ + if (op->type == tok_operator && op->content == "<=") + { return lhs <= rhs; } + else if (op->type == tok_operator && op->content == ">=") + { return lhs >= rhs; } + else if (op->type == tok_operator && op->content == "<") + { return lhs < rhs; } + else if (op->type == tok_operator && op->content == ">") + { return lhs > rhs; } + else if (op->type == tok_operator && op->content == "==") + { return lhs == rhs; } + else if (op->type == tok_operator && op->content == "!=") + { return lhs != rhs; } + else + throw parse_error ("expected comparison operator", op); +} + + // Here, we perform on-the-fly preprocessing. // The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %) // where CONDITION is: kernel_v[r] COMPARISON-OP "version-string" @@ -159,7 +180,7 @@ parser::last () // The %: ELSE-TOKENS part is optional. // // e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %) -// e.g. %( arch != "i686" %? "foo" %: "baz" %) +// e.g. %( arch != "i?86" %? "foo" %: "baz" %) // // Up to an entire %( ... %) expression is processed by a single call // to this function. Tokens included by any nested conditions are @@ -241,35 +262,19 @@ bool eval_pp_conditional (systemtap_session& s, return result; } - else if ((l->type == tok_string && r->type == tok_string) - || (l->type == tok_number && r->type == tok_number)) + else if (l->type == tok_string && r->type == tok_string) { - // collect acceptable strverscmp results. - int rvc_ok1, rvc_ok2; - if (op->type == tok_operator && op->content == "<=") - { rvc_ok1 = -1; rvc_ok2 = 0; } - else if (op->type == tok_operator && op->content == ">=") - { rvc_ok1 = 1; rvc_ok2 = 0; } - else if (op->type == tok_operator && op->content == "<") - { rvc_ok1 = -1; rvc_ok2 = -1; } - else if (op->type == tok_operator && op->content == ">") - { rvc_ok1 = 1; rvc_ok2 = 1; } - else if (op->type == tok_operator && op->content == "==") - { rvc_ok1 = 0; rvc_ok2 = 0; } - else if (op->type == tok_operator && op->content == "!=") - { rvc_ok1 = -1; rvc_ok2 = 1; } - else - throw parse_error ("expected comparison operator", op); - - int rvc_result = l->content.compare(r->content); - - // normalize rvc_result - if (rvc_result < 0) rvc_result = -1; - if (rvc_result > 0) rvc_result = 1; - + string lhs = l->content; + string rhs = r->content; + return eval_comparison (lhs, op, rhs); + // NB: no wildcarding option here + } + else if (l->type == tok_number && r->type == tok_number) + { + int64_t lhs = lex_cast<int64_t>(l->content); + int64_t rhs = lex_cast<int64_t>(r->content); + return eval_comparison (lhs, op, rhs); // NB: no wildcarding option here - - return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2); } else if (l->type == tok_string && r->type == tok_number && op->type == tok_operator) @@ -277,17 +282,18 @@ bool eval_pp_conditional (systemtap_session& s, else if (l->type == tok_number && r->type == tok_string && op->type == tok_operator) throw parse_error ("expected number literal as right value", r); + // XXX: support other forms? "CONFIG_SMP" ? + else throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'\n" " or comparison between strings or integers", l); } -// expand_args is used to know if we must expand $x and @x identifiers. // Only tokens corresponding to the TRUE statement must be expanded const token* -parser::scan_pp (bool wildcard, bool expand_args) +parser::scan_pp (bool wildcard) { while (true) { @@ -298,7 +304,7 @@ parser::scan_pp (bool wildcard, bool expand_args) return t; } - const token* t = input.scan (wildcard, expand_args); // NB: not recursive! + const token* t = input.scan (wildcard); // NB: not recursive! if (t == 0) // EOF return t; @@ -308,77 +314,108 @@ parser::scan_pp (bool wildcard, bool expand_args) // We have a %( - it's time to throw a preprocessing party! const token *l, *op, *r; - l = input.scan (false, expand_args); // NB: not recursive, though perhaps could be - op = input.scan (false, expand_args); - r = input.scan (false, expand_args); + l = input.scan (false); // NB: not recursive, though perhaps could be + op = input.scan (false); + r = input.scan (false); if (l == 0 || op == 0 || r == 0) throw parse_error ("incomplete condition after '%('", t); // NB: consider generalizing to consume all tokens until %?, and // passing that as a vector to an evaluator. // Do not evaluate the condition if we haven't expanded everything. - // This may occured when having several recursive conditionals. - bool result = expand_args && eval_pp_conditional (session, l, op, r); + // This may occur when having several recursive conditionals. + bool result = eval_pp_conditional (session, l, op, r); delete l; delete op; delete r; - + + /* + clog << "PP eval (" << *t << ") == " << result << endl; + */ + const token *m = input.scan (); // NB: not recursive if (! (m && m->type == tok_operator && m->content == "%?")) throw parse_error ("expected '%?' marker for conditional", t); delete m; // "%?" vector<const token*> my_enqueued_pp; - bool have_token = false; - + + int nesting = 0; while (true) // consume THEN tokens { - m = scan_pp (wildcard, result); // NB: recursive - if (m == 0) - throw parse_error (have_token ? - "incomplete conditional - missing %: or %)" : - "missing THEN tokens for conditional", - t); - - have_token = true; - if (m->type == tok_operator && (m->content == "%:" || // ELSE - m->content == "%)")) // END + try + { + m = result ? scan_pp (wildcard) : input.scan (wildcard); + } + catch (const parse_error &e) + { + if (result) throw e; // propagate errors if THEN branch taken + continue; + } + + if (m && m->type == tok_operator && m->content == "%(") // nested %( + nesting ++; + if (nesting == 0 && m && (m->type == tok_operator && (m->content == "%:" || // ELSE + m->content == "%)"))) // END break; - // enqueue token - if (result) + if (nesting && m && m->type == tok_operator && m->content == "%)") // nested %) + nesting --; + + if (!m) + throw parse_error ("incomplete conditional - missing '%:' or '%)'", t); + if (result) my_enqueued_pp.push_back (m); - else - delete m; // unused token - // continue + if (!result) + delete m; // do nothing, just dispose of unkept THEN token + + continue; } - have_token = false; if (m && m->type == tok_operator && m->content == "%:") // ELSE { delete m; // "%:" + int nesting = 0; while (true) { - m = scan_pp (wildcard, expand_args && !result); // NB: recursive - if (m == 0) - throw parse_error (have_token ? - "incomplete conditional - missing %)" : - "missing ELSE tokens for conditional", - t); - - have_token = true; - if (m->type == tok_operator && m->content == "%)") // END + try + { + m = result ? input.scan (wildcard) : scan_pp (wildcard); + } + catch (const parse_error& e) + { + if (!result) throw e; // propagate errors if ELSE branch taken + continue; + } + + if (m && m->type == tok_operator && m->content == "%(") // nested %( + nesting ++; + if (nesting == 0 && m && m->type == tok_operator && m->content == "%)") // END break; - // enqueue token - if (! result) - my_enqueued_pp.push_back (m); - else - delete m; // unused token - // continue + if (nesting && m && m->type == tok_operator && m->content == "%)") // nested %) + nesting --; + + if (!m) + throw parse_error ("incomplete conditional - missing %)", t); + if (!result) + my_enqueued_pp.push_back (m); + if (result) + delete m; // do nothing, just dispose of unkept ELSE token + + continue; } } + + /* + clog << "PP eval (" << *t << ") == " << result << " tokens: " << endl; + for (unsigned k=0; k<my_enqueued_pp.size(); k++) + clog << * my_enqueued_pp[k] << endl; + clog << endl; + */ + delete t; // "%(" delete m; // "%)" + // NB: we transcribe the retained tokens here, and not inside // the THEN/ELSE while loops. If it were done there, each loop // would become infinite (each iteration consuming an ordinary @@ -598,7 +635,7 @@ lexer::input_put (const string& chars) token* -lexer::scan (bool wildcard, bool expand_args) +lexer::scan (bool wildcard) { token* n = new token; n->location.file = input_name; @@ -633,8 +670,7 @@ lexer::scan (bool wildcard, bool expand_args) // characters; @1..@999 are quoted/escaped as strings. // $# and @# expand to the number of arguments, similarly // raw or quoted. - if (expand_args && - (c == '$' || c == '@') && + if ((c == '$' || c == '@') && (c2 == '#')) { input_get(); // swallow '#' @@ -645,8 +681,7 @@ lexer::scan (bool wildcard, bool expand_args) semiskipped_p ++; goto semiskip; } - else if (expand_args && - (c == '$' || c == '@') && + else if ((c == '$' || c == '@') && (isdigit (c2))) { unsigned idx = 0; @@ -660,7 +695,8 @@ lexer::scan (bool wildcard, bool expand_args) idx <= session.args.size()); // prevent overflow if (idx == 0 || idx-1 >= session.args.size()) - throw parse_error ("command line argument index invalid or out of range", n); + throw parse_error ("command line argument index " + lex_cast<string>(idx) + + " out of range [1-" + lex_cast<string>(session.args.size()) + "]", n); string arg = session.args[idx-1]; if (c == '$') input_put (arg); @@ -69,7 +69,7 @@ struct systemtap_session; class lexer { public: - token* scan (bool wildcard=false, bool expand_args=true); + token* scan (bool wildcard=false); lexer (std::istream&, const std::string&, systemtap_session&); private: @@ -132,7 +132,7 @@ private: // preprocessing subordinate std::vector<const token*> enqueued_pp; - const token* scan_pp (bool wildcard=false, bool expand_args=true); + const token* scan_pp (bool wildcard=false); // scanning state const token* last (); diff --git a/runtime/ChangeLog b/runtime/ChangeLog index bdf6e56d..fb92dccc 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,117 @@ +2008-06-23 David Smith <dsmith@redhat.com> + + * task_finder.c (__stp_utrace_task_finder_report_exec): Handles + relative exec paths correctly. + + * task_finder_vma.c (__stp_tf_vma_hash): Improved determination of + whether this is a 64-bit platform. + * syscall.h: Handles kernels with older style register + definitions. + + * task_finder.c (__stp_tf_vm_cb): New function. + (stap_register_task_finder_target): Sets up syscall entry and + syscall exit handlers. + (__stp_find_file_based_vma): New function. + (__stp_utrace_task_finder_target_syscall_entry): New function. + Saves vma information off at syscall entry. + (__stp_target_call_vm_callback): New function. + (__stp_utrace_task_finder_target_syscall_exit): New function. + Handles changes to memory maps based on information saved at + syscall entry. + * syscall.h: New file containing syscall function. + * task_finder_vma.c: New file containing saved vma information + handling functions. + + * regs.h: Removed trailing semicolons from macro definitions. + +2008-06-17 David Smith <dsmith@redhat.com> + + * task_finder.c (__stp_utrace_attach_match_filename): Uses new + __STP_ATTACHED_TASK_EVENTS macro to determine which events to set + on a newly found process based on whether the + stap_task_finder_target structure has a vm_callback defined. + (stap_start_task_finder): Ditto. + +2008-06-16 David Smith <dsmith@redhat.com> + + * task_finder.c (stap_start_task_finder): Improved callback + handling. + +2008-06-10 David Smith <dsmith@redhat.com> + + * task_finder.c (struct stap_task_finder_target): Added + vm_callback public field. + (stap_register_task_finder_target): Sets up .report_quiesce + handler. + (__stp_utrace_task_finder_target_quiesce): New function. + +2008-06-09 David Smith <dsmith@redhat.com> + + * task_finder.c (__stp_utrace_task_finder_report_exec): Handles + 2.6.25 kernels. + +2008-06-06 David Smith <dsmith@redhat.com> + + * task_finder.c: Added some debug logic. Use + '-DDEBUG_TASK_FINDER' to enable. + (stap_utrace_attach): Renamed from '__stp_utrace_attach'. + (__stp_utrace_attach_match_filename): Calls callback with + notification that this is a process or thread event. + (__stp_utrace_attach_match_tsk): Ditto. + (__stp_utrace_task_finder_report_clone): Ditto. + (__stp_utrace_task_finder_report_exec): Ditto. + (stap_utrace_task_finder_report_death): Ditto. + (stap_start_task_finder): Ditto. + (stap_stop_task_finder): Added debug logic. + +2008-05-29 Stan Cox <scox@redhat.com> + + * map.c (print_keytype): Remove. + (print_valtype): Remove. + (_stp_map_printn): Remove. + (_stp_map_print): Remove. + (_stp_pmap_printn): Remove. + * stat-common.c (_stp_stat_print_valtype): Remove. + * stat.c (__stp_stat_print): Remove. + (_stp_stat_print_cpu): Remove. + (_stp_stat_print): Remove. + * Makefile: Delete. + * tests: Delete. + * probes: Delete. + +2008-05-28 David Smith <dsmith@redhat.com> + + * task_finder.c (__stp_utrace_attach_match_filename): Added + register_p parameter, which is passed on to the callback. Only + adds death notification if register_p is 1. If register_p is 0, + removes death notification. + (__stp_utrace_attach_match_tsk): Moved code from + __stp_utrace_task_finder_report_clone that handles the details of + grabbing a task's path. + (__stp_utrace_task_finder_report_clone): Calls new + __stp_utrace_attach_match_tsk(). + (__stp_utrace_task_finder_report_exec): Notifies upper layer that + it might need to detach from newly exec'ed process.` + +2008-05-27 Josh Stone <joshua.i.stone@intel.com> + + PR 6432 + * loc2c-runtime.h (kread, kwrite, deref, store_deref): Add + architecture-neutral implementations, using probe_kernel_* + facilites (controlled by autoconf). + * autoconf-probe-kernel.c: test for above. + +2008-05-21 David Smith <dsmith@redhat.com> + + * task_finder.c (__stp_utrace_attach_match_filename): Added + event_flag parameter of event to pass to callback. + (__stp_utrace_task_finder_target_death): Ditto. + (__stp_utrace_task_finder_report_clone): Calls + __stp_utrace_attach_match_filename() with new argument. + (__stp_utrace_task_finder_report_exec): Ditto. + (stap_start_task_finder): Calls callback with an invalid + event_flag since this callback call isn't related to an event. + 2008-05-16 David Smith <dsmith@redhat.com> PR 6499. diff --git a/runtime/Makefile b/runtime/Makefile deleted file mode 100644 index 22d25ff9..00000000 --- a/runtime/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for SystemTap runtime and example probes -# - -all: - make -w -C stpd - cd probes; ./build - -relayfs: - make -w -C relayfs - -clean: - make -w -C relayfs clean - make -w -C stpd clean - cd probes; ./build clean diff --git a/runtime/autoconf-probe-kernel.c b/runtime/autoconf-probe-kernel.c new file mode 100644 index 00000000..93fbaae6 --- /dev/null +++ b/runtime/autoconf-probe-kernel.c @@ -0,0 +1,7 @@ +#include <linux/uaccess.h> + +void probe_kernel(void *dst, void *src, size_t size) +{ + (void)probe_kernel_read(dst, src, size); + (void)probe_kernel_write(dst, src, size); +} diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 66fd1e43..a7472691 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -9,6 +9,7 @@ * later version. */ +#include <linux/uaccess.h> #include <linux/types.h> #define intptr_t long #define uintptr_t unsigned long @@ -31,9 +32,6 @@ << (sizeof (base) * 8 - (higherbits) - (nbits)))) -/* These operations are target-specific. */ -#include <asm/uaccess.h> - /* Given a DWARF register number, fetch its intptr_t (long) value from the probe context, or store a new value into the probe context. @@ -173,6 +171,61 @@ #endif + +/* NB: this autoconf is always disabled, pending further performance eval. */ +#if defined STAPCONF_PROBE_KERNEL + +/* Kernel 2.6.26 adds probe_kernel_{read,write}, which lets us write + * architecture-neutral implementations of kread, kwrite, deref, and + * store_deref. + * + * NB: deref and store_deref shouldn't be used with 64-bit values on 32-bit + * platforms, because they will lose data in the conversion to intptr_t. We + * generally want to encourage using kread and kwrite instead. + */ + +#define kread(ptr) ({ \ + typeof(*(ptr)) _v; \ + if (probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ + DEREF_FAULT(ptr); \ + _v; \ + }) + +#define kwrite(ptr, value) ({ \ + typeof(*(ptr)) _v; \ + _v = (typeof(*(ptr)))(value); \ + if (probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ + STORE_DEREF_FAULT(ptr); \ + }) + +#define deref(size, addr) ({ \ + intptr_t _i; \ + switch (size) { \ + case 1: _i = kread((u8 *)(addr)); break; \ + case 2: _i = kread((u16 *)(addr)); break; \ + case 4: _i = kread((u32 *)(addr)); break; \ + case 8: _i = kread((u64 *)(addr)); break; \ + default: __deref_bad(); \ + /* uninitialized _i should also be caught by -Werror */ \ + } \ + _i; \ + }) + +#define store_deref(size, addr, value) ({ \ + switch (size) { \ + case 1: kwrite((u8 *)(addr), (value)); break; \ + case 2: kwrite((u16 *)(addr), (value)); break; \ + case 4: kwrite((u32 *)(addr), (value)); break; \ + case 8: kwrite((u64 *)(addr), (value)); break; \ + default: __store_deref_bad(); \ + } \ + }) + +extern void __deref_bad(void); +extern void __store_deref_bad(void); + +#else /* !STAPCONF_PROBE_KERNEL */ + #if defined __i386__ #define deref(size, addr) \ @@ -614,38 +667,6 @@ #endif /* (s390) || (s390x) */ -#define deref_string(dst, addr, maxbytes) \ - ({ \ - uintptr_t _addr; \ - size_t _len; \ - unsigned char _c; \ - char *_d = (dst); \ - for (_len = (maxbytes), _addr = (uintptr_t)(addr); \ - _len > 1 && (_c = deref (1, _addr)) != '\0'; \ - --_len, ++_addr) \ - 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); \ - }) - #if defined __i386__ @@ -678,6 +699,40 @@ #endif +#endif /* STAPCONF_PROBE_KERNEL */ + +#define deref_string(dst, addr, maxbytes) \ + ({ \ + uintptr_t _addr; \ + size_t _len; \ + unsigned char _c; \ + char *_d = (dst); \ + for (_len = (maxbytes), _addr = (uintptr_t)(addr); \ + _len > 1 && (_c = deref (1, _addr)) != '\0'; \ + --_len, ++_addr) \ + 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); \ + }) + #define CATCH_DEREF_FAULT() \ if (0) { \ deref_fault: ; \ diff --git a/runtime/map.c b/runtime/map.c index a436d7ed..bb221cd2 100644 --- a/runtime/map.c +++ b/runtime/map.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Map Functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005, 2006, 2007, 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 @@ -631,130 +631,6 @@ void _stp_map_sortn(MAP map, int n, int keynum, int dir) } } -static int print_keytype (char *fmt, int type, key_data *kd) -{ - //dbug ("*fmt = %c\n", *fmt); - switch (type) { - case STRING: - if (*fmt != 's') - return 1; - _stp_print (kd->strp); - break; - case INT64: - if (*fmt == 'x') - _stp_printf("%llx", kd->val); - else if (*fmt == 'X') - _stp_printf("%llX", kd->val); - else if (*fmt == 'd') - _stp_printf("%lld", kd->val); - else if (*fmt == 'p') { -#if BITS_PER_LONG == 64 - _stp_printf("%016llx", kd->val); -#else - _stp_printf("%08llx", kd->val); -#endif - } else if (*fmt == 'P') - _stp_symbol_print ((unsigned long)kd->val); - else - return 1; - break; - default: - return 1; - break; - } - return 0; -} - -static void print_valtype (MAP map, char *fmt, struct map_node *ptr) -{ - switch (map->type) { - case STRING: - if (*fmt == 's') - _stp_print (_stp_get_str(ptr)); - break; - case INT64: - { - int64_t val = _stp_get_int64(ptr); - if (*fmt == 'x') - _stp_printf("%llx", val); - else if (*fmt == 'X') - _stp_printf("%llX", val); - else if (*fmt == 'd') - _stp_printf("%lld", val); - else if (*fmt == 'p') { -#if BITS_PER_LONG == 64 - _stp_printf("%016llx", val); -#else - _stp_printf("%08llx", val); -#endif - } else if (*fmt == 'P') - _stp_symbol_print ((unsigned long)val); - break; - } - case STAT: - { - stat *sd = _stp_get_stat(ptr); - _stp_stat_print_valtype (fmt, &map->hist, sd, 0); - break; - } - default: - break; - } -} - -/** Print a Map. - * Print a Map using a format string. - * - * @param map Map - * @param fmt @ref format_string - */ -void _stp_map_printn (MAP map, int n, const char *fmt) -{ - struct map_node *ptr; - int type, num; - key_data kd; - - if (n < 0) - return; - - foreach (map, ptr) { - char *f = (char *)fmt; - while (*f) { - f = next_fmt (f, &num); - if (num) { - /* key */ - kd = (*map->get_key)(ptr, num, &type); - if (type != END) - print_keytype (f, type, &kd); - } else { - /* value */ - print_valtype (map, f, ptr); - } - if (*f) - f++; - } - _stp_print_char ('\n'); - if (n && (--n <= 0)) - break; - } - _stp_print_char ('\n'); - _stp_print_flush(); -} - -/** Print a Map. - * Print a Map using a format string. - * - * @param map Map - * @param fmt @ref format_string - */ -#define _stp_map_print(map,fmt) _stp_map_printn(map,0,fmt) - -void _stp_pmap_printn_cpu (PMAP pmap, int n, const char *fmt, int cpu) -{ - MAP m = per_cpu_ptr (pmap->map, cpu); - _stp_map_printn (m, n, fmt); -} - static struct map_node *_stp_new_agg(MAP agg, struct hlist_head *ahead, struct map_node *ptr) { struct map_node *aptr; @@ -911,8 +787,8 @@ MAP _stp_pmap_agg (PMAP pmap) */ #define _stp_pmap_get_agg(pmap) (&pmap->agg) -#define _stp_pmap_printn(map,n,fmt) _stp_map_printn (_stp_pmap_agg(map), n, fmt) -#define _stp_pmap_print(map,fmt) _stp_map_printn(_stp_pmap_agg(map),0,fmt) +/* #define _stp_pmap_printn(map,n,fmt) _stp_map_printn (_stp_pmap_agg(map), n, fmt) */ +/* #define _stp_pmap_print(map,fmt) _stp_map_printn(_stp_pmap_agg(map),0,fmt) */ static void _new_map_clear_node (struct map_node *m) { diff --git a/runtime/probes/ChangeLog b/runtime/probes/ChangeLog deleted file mode 100644 index 47976f5c..00000000 --- a/runtime/probes/ChangeLog +++ /dev/null @@ -1,113 +0,0 @@ -2006-09-26 David Smith <dsmith@redhat.com> - - * bench/run_bench: Changed 'stpd' references to 'staprun'. - * bench/trans_bench: Ditto. - * where_func/README: Ditto. - -2005-11-08 Martin Hunt <hunt@redhat.com> - - * shellsnoop/shellsnoop.c: Updated to use new map API. - * where_func/kprobe_where_funct.c: Ditto. - * os_timer/os_timer.c (probe_start): Ditto. - * test4/test4.c: Ditto. - * scf/scf.c: Ditto. - -2005-09-08 Martin Hunt <hunt@redhat.com> - - * scf/scf.c (inst_smp_call_function): Add new verbose arg - to _stp_stack_sprint() call. - -2005-08-31 Martin Hunt <hunt@redhat.com> - - * Makefile.template: Remove KTA, KALLSYMS_LOOKUP, - and KALLSYMS_LOOKUP_NAME - -2005-08-19 Martin Hunt <hunt@redhat.com> - - * shellsnoop/shellsnoop.c: Remove STP_NETLINK_ONLY. - * stp: Deleted. Use stpd directly. - - -2005-08-01 Martin Hunt <hunt@redhat.com> - - * agg/stat1.c (probe_exit): Remove "static" - * agg/count1.c (probe_exit): Ditto. - * agg/count2.c (probe_exit): Ditto. - * bench/bench_io2.c (probe_exit): Ditto. - * bench/bench_io1.c (probe_exit): Ditto. - * bench/bench.c (probe_exit): Ditto. - * bench/bench_ret.c (probe_exit): Ditto. - * bench/bench_multi.c (probe_exit): Ditto. - * where_func/kprobe_where_funct.c (probe_exit): Ditto. - * test4/test4.c (probe_exit): Ditto. - * tasklet/stp_tasklet.c (probe_exit): Ditto. - * os_timer/os_timer.c (probe_exit): Ditto. - * scf/scf.c (probe_exit): Ditto. - -2005-07-28 Martin Hunt <hunt@redhat.com> - - * bench/ALL: Chnage to probe sys_getuid() and sys_getgid() - because those aren't used by stpd, unlike sys_read() and sys_write(). - -2005-07-11 Martin Hunt <hunt@redhat.com> - - * build_probe: Set RELAYFS correctly. - - * Makefile.template: Fix for RELAYFS. - - * stp: Moved here. All probes now use this copy. - - * ALL/stp: source the master copy of stp. - -2005-07-08 Martin Hunt <hunt@redhat.com> - - * ALL: Use new runtime.h. Change init_module() - to probe_start() and don't do transport calls. - Remove MODULE_LICENSE and cleanup_module(). - -2005-07-01 Martin Hunt <hunt@redhat.com> - - * Makefile.template (debug): New target. - - * build: Support "debug" target. - - * build_probe: Ditto. - -2005-06-28 Martin Hunt <hunt@redhat.com> - - * bench/bench_ret.c (inst_sys_write_ret): Fix prototype. - - * bench: New probe to do benchmarks. - -2005-06-23 Martin Hunt <hunt@redhat.com> - - * all probes: Modified to use latest changes to transport.h. - -2005-06-21 Martin Hunt <hunt@redhat.com> - - * build_probe (build): Add relay_flush and relay_switch_subbuf to the - list of undefines to ignore. - -2005-06-20 Tom Zanussi <zanussi@us.ibm.com> - - * added transport_mode, subbuf_size, n_subbufs to all - probes and changed _stp_transport_open() calls. - - * removed all obsolete params from stp scripts. - -2005-06-18 Martin Hunt <hunt@redhat.com> - - * build: Modified to use build_probe. - - * build_probe: New file. This does the work of building - a single probe or set of probes in a directory. - - * Makefile.template: New file. Template used by - build_probe to create Makefiles. - - * agg: New set of probes to test/demonstrate - Counter and Stat aggregations. - - * all probes modified for latest changes and new build - process. - diff --git a/runtime/probes/Makefile.template b/runtime/probes/Makefile.template deleted file mode 100644 index 5d770e95..00000000 --- a/runtime/probes/Makefile.template +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile -PWD := $(shell pwd) -RT := $(PWD)/../.. -KVERSION := $(shell uname -r) -KDIR := /lib/modules/$(KVERSION)/build include - -FLAGS := -I $(RT) RELAYFS - -DFLAGS := $(FLAGS) -D DEBUG - -obj-m := XXX.o - -default: - $(MAKE) V=1 -C $(KDIR) M=$(PWD) RT=$(RT) EXTRA_CFLAGS="$(FLAGS)" modules - -debug: - $(MAKE) V=1 -C $(KDIR) M=$(PWD) RT=$(RT) EXTRA_CFLAGS="$(DFLAGS)" modules - - -clean: - /bin/rm -rf *.o *.o.d *.ko *~ *.mod.c .*.cmd .tmp_versions diff --git a/runtime/probes/README b/runtime/probes/README deleted file mode 100644 index f3cd9fb2..00000000 --- a/runtime/probes/README +++ /dev/null @@ -1,10 +0,0 @@ -/** @dir probes -This directory contains working example probes that demonstrate and test -the runtime library. They are tested on i386 and x86_64. -*/ - -To build all probes, just type "./build" -To clean up, "./build clean" -To see a verbose build "./build -v" - -The same commands work in any probe subdirectory. diff --git a/runtime/probes/agg/README b/runtime/probes/agg/README deleted file mode 100644 index b48db1b8..00000000 --- a/runtime/probes/agg/README +++ /dev/null @@ -1,3 +0,0 @@ -/** @dir agg -Test probes to use the Counter and Stat aggregations. -*/ diff --git a/runtime/probes/agg/build b/runtime/probes/agg/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/agg/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/agg/count1.c b/runtime/probes/agg/count1.c deleted file mode 100644 index 731b236b..00000000 --- a/runtime/probes/agg/count1.c +++ /dev/null @@ -1,102 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 - -#include "runtime.h" - -#include "counter.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: count1"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - -Counter opens; -Counter reads; -Counter writes; -Counter sched; -Counter idle; - -static int inst_sys_open (struct kprobe *p, struct pt_regs *regs) -{ - _stp_counter_add (opens, 1); - return 0; -} - -static int inst_sys_read (struct kprobe *p, struct pt_regs *regs) -{ - _stp_counter_add (reads, 1); - return 0; -} - -static int inst_sys_write (struct kprobe *p, struct pt_regs *regs) -{ - _stp_counter_add (writes, 1); - return 0; -} - -static int inst_schedule(struct kprobe *p, struct pt_regs *regs) -{ - _stp_counter_add (sched, 1); - return 0; -} - -static int inst_idle_cpu(struct kprobe *p, struct pt_regs *regs) -{ - _stp_counter_add (idle, 1); - return 0; -} - -static struct kprobe stp_probes[] = { - { - .addr = "sys_open", - .pre_handler = inst_sys_open - }, - { - .addr = "sys_read", - .pre_handler = inst_sys_read - }, - { - .addr = "sys_write", - .pre_handler = inst_sys_write - }, - { - .addr = "schedule", - .pre_handler = inst_schedule - }, - { - .addr = "idle_cpu", - .pre_handler = inst_idle_cpu - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct kprobe)) - -int probe_start(void) -{ - opens = _stp_counter_init(); - reads = _stp_counter_init(); - writes = _stp_counter_init(); - sched = _stp_counter_init(); - idle = _stp_counter_init(); - - return _stp_register_kprobes (stp_probes, MAX_STP_ROUTINE); -} - -void probe_exit (void) -{ - int i; - - _stp_unregister_kprobes (stp_probes, MAX_STP_ROUTINE); - - for_each_cpu(i) - _stp_printf ("sched calls for cpu %d = %lld\n", i, _stp_counter_get_cpu(sched, i, 0)); - - _stp_print ("\n\n"); - - _stp_printf ("open calls: %lld\n", _stp_counter_get(opens, 0)); - _stp_printf ("read calls: %lld\n", _stp_counter_get(reads, 0)); - _stp_printf ("write calls: %lld\n", _stp_counter_get(writes, 0)); - _stp_printf ("sched calls: %lld\n", _stp_counter_get(sched, 0)); - _stp_printf ("idle calls: %lld\n", _stp_counter_get(idle, 0)); - _stp_print_flush(); -} - diff --git a/runtime/probes/agg/count2.c b/runtime/probes/agg/count2.c deleted file mode 100644 index 23987759..00000000 --- a/runtime/probes/agg/count2.c +++ /dev/null @@ -1,81 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 -#include "runtime.h" - -#include "counter.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: count2"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - -Counter opens; -Counter reads; -Counter writes; -Counter read_bytes; -Counter write_bytes; - -asmlinkage long inst_sys_open (const char __user * filename, int flags, int mode) -{ - _stp_counter_add (opens, 1); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_read (unsigned int fd, char __user * buf, size_t count) -{ - _stp_counter_add (reads, 1); - _stp_counter_add (read_bytes, count); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_write (unsigned int fd, const char __user * buf, size_t count) -{ - _stp_counter_add (writes, 1); - _stp_counter_add (write_bytes, count); - jprobe_return(); - return 0; -} - -static struct jprobe stp_probes[] = { - { - .kp.addr = (kprobe_opcode_t *)"sys_open", - .entry = (kprobe_opcode_t *) inst_sys_open - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_read", - .entry = (kprobe_opcode_t *) inst_sys_read - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_write", - .entry = (kprobe_opcode_t *) inst_sys_write - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct jprobe)) - -int probe_start(void) -{ - opens = _stp_counter_init(); - reads = _stp_counter_init(); - writes = _stp_counter_init(); - read_bytes = _stp_counter_init(); - write_bytes = _stp_counter_init(); - - return _stp_register_jprobes (stp_probes, MAX_STP_ROUTINE); -} - -void probe_exit (void) -{ - int i; - - _stp_unregister_jprobes (stp_probes, MAX_STP_ROUTINE); - - _stp_printf ("open calls: %lld\n", _stp_counter_get(opens, 0)); - _stp_printf ("read calls: %lld\n", _stp_counter_get(reads, 0)); - _stp_printf ("read bytes: %lld\n", _stp_counter_get(read_bytes, 0)); - _stp_printf ("write calls: %lld\n", _stp_counter_get(writes, 0)); - _stp_printf ("write bytes: %lld\n", _stp_counter_get(write_bytes, 0)); - - _stp_print_flush(); -} diff --git a/runtime/probes/agg/stat1.c b/runtime/probes/agg/stat1.c deleted file mode 100644 index 4e0cf961..00000000 --- a/runtime/probes/agg/stat1.c +++ /dev/null @@ -1,72 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 -#include "runtime.h" -#include "stat.c" -#include "counter.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: stat1"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - - -Counter opens; -Stat reads; -Stat writes; - -asmlinkage long inst_sys_open (const char __user * filename, int flags, int mode) -{ - _stp_counter_add (opens, 1); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_read (unsigned int fd, char __user * buf, size_t count) -{ - _stp_stat_add (reads, count); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_write (unsigned int fd, const char __user * buf, size_t count) -{ - _stp_stat_add (writes, count); - jprobe_return(); - return 0; -} - -static struct jprobe stp_probes[] = { - { - .kp.addr = (kprobe_opcode_t *)"sys_open", - .entry = (kprobe_opcode_t *) inst_sys_open - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_read", - .entry = (kprobe_opcode_t *) inst_sys_read - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_write", - .entry = (kprobe_opcode_t *) inst_sys_write - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct jprobe)) - -int probe_start(void) -{ - opens = _stp_counter_init(); - reads = _stp_stat_init(HIST_LOG,24); - writes = _stp_stat_init(HIST_LINEAR,0,1000,50); - - return _stp_register_jprobes (stp_probes, MAX_STP_ROUTINE); -} - -void probe_exit (void) -{ - _stp_unregister_jprobes (stp_probes, MAX_STP_ROUTINE); - - _stp_printf ("OPENS: %lld\n", _stp_counter_get(opens, 0)); - _stp_stat_print (reads, "READS: count:%C sum:%S avg:%A min:%m max:%M\n%H", 0); - _stp_stat_print (writes, "WRITES: count:%C sum:%S avg:%A min:%m max:%M\n%H", 0); - - _stp_print_flush(); -} diff --git a/runtime/probes/agg/targets b/runtime/probes/agg/targets deleted file mode 100644 index 614a00d2..00000000 --- a/runtime/probes/agg/targets +++ /dev/null @@ -1,3 +0,0 @@ -count1 -count2 -stat1 diff --git a/runtime/probes/bench/Makefile b/runtime/probes/bench/Makefile deleted file mode 100644 index 9154e3dc..00000000 --- a/runtime/probes/bench/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: ttest itest - -ttest: ttest.c - gcc -Wall -O3 -o ttest ttest.c - -itest: itest.c - gcc -Wall -O3 -o itest itest.c - -clean: - /bin/rm -f itest ttest stpd_cpu* xxx* diff --git a/runtime/probes/bench/README b/runtime/probes/bench/README deleted file mode 100644 index 04801a74..00000000 --- a/runtime/probes/bench/README +++ /dev/null @@ -1,18 +0,0 @@ -This is a benchmark program for the SystemTap Runtime. - -It works by instrumenting sys_uid() and sys_gid(). It calls each a million -times and measures how long it takes. Then it puts an empty kprobe on one and jprobe on the -other and measures that. Subtracting the difference between the two runs gives -the kprobe and jprobe overhead. The process is then repeated for more -complicated probes. - -To Start: - -1. Build the test program. -> gcc -O3 -o time time.c - -2. Run the benchmarks -> ./run_bench - - - diff --git a/runtime/probes/bench/bench.c b/runtime/probes/bench/bench.c deleted file mode 100644 index a00efa05..00000000 --- a/runtime/probes/bench/bench.c +++ /dev/null @@ -1,51 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench"); -MODULE_AUTHOR("Martin Hunt"); - -asmlinkage ssize_t inst_sys_getgid (unsigned int fd, const char __user * buf, size_t count) -{ - jprobe_return(); - return 0; -} - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} - -static struct jprobe jp[] = { - { - .kp.addr = (kprobe_opcode_t *)"sys_getgid", - .entry = (kprobe_opcode_t *) inst_sys_getgid - }, -}; - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid - } -}; - -#define NUM_JPROBES (sizeof(jp)/sizeof(struct jprobe)) -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - int ret = _stp_register_jprobes (jp, NUM_JPROBES); - if (ret >= 0) - if ((ret = _stp_register_kprobes (kp, NUM_KPROBES)) < 0) - _stp_unregister_jprobes (jp, NUM_JPROBES); - return ret; -} - -void probe_exit (void) -{ - _stp_unregister_jprobes (jp, NUM_JPROBES); - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_io1.c b/runtime/probes/bench/bench_io1.c deleted file mode 100644 index 8bdc4018..00000000 --- a/runtime/probes/bench/bench_io1.c +++ /dev/null @@ -1,46 +0,0 @@ -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_io1"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 100 chars */ - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - -static int inst_sys_getgid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 100 chars */ - _stp_print_cstr ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid - } -}; - -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - return _stp_register_kprobes (kp, NUM_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_io2.c b/runtime/probes/bench/bench_io2.c deleted file mode 100644 index 14216913..00000000 --- a/runtime/probes/bench/bench_io2.c +++ /dev/null @@ -1,47 +0,0 @@ -#define STP_RELAYFS -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_io2"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 100 chars */ - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - -static int inst_sys_getgid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 100 chars */ - _stp_print_cstr ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid - } -}; - -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - return _stp_register_kprobes (kp, NUM_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_io3.c b/runtime/probes/bench/bench_io3.c deleted file mode 100644 index a491edd9..00000000 --- a/runtime/probes/bench/bench_io3.c +++ /dev/null @@ -1,44 +0,0 @@ -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_io3"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 1000 chars */ - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid - }, -}; - -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - return _stp_register_kprobes (kp, NUM_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_io4.c b/runtime/probes/bench/bench_io4.c deleted file mode 100644 index a6b19ab5..00000000 --- a/runtime/probes/bench/bench_io4.c +++ /dev/null @@ -1,45 +0,0 @@ -#define STP_RELAYFS -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_io3"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - /* print 1000 chars */ - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_printf ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); - _stp_print_flush(); - return 0; -} - - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid - }, -}; - -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - return _stp_register_kprobes (kp, NUM_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_multi.c b/runtime/probes/bench/bench_multi.c deleted file mode 100644 index a6dc38a4..00000000 --- a/runtime/probes/bench/bench_multi.c +++ /dev/null @@ -1,73 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_multi"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid1 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} -static int inst_sys_getuid2 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} - -static int inst_sys_getgid1 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} -static int inst_sys_getgid2 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} -static int inst_sys_getgid3 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} -static int inst_sys_getgid4 (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} - -static struct kprobe kp[] = { - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid1 - }, - { - .addr = "sys_getuid", - .pre_handler = inst_sys_getuid2 - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid1 - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid2 - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid3 - }, - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid4 - } -}; - -#define NUM_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - return _stp_register_kprobes (kp, NUM_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, NUM_KPROBES); -} diff --git a/runtime/probes/bench/bench_ret.c b/runtime/probes/bench/bench_ret.c deleted file mode 100644 index 40f2ddad..00000000 --- a/runtime/probes/bench/bench_ret.c +++ /dev/null @@ -1,61 +0,0 @@ -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 -#define USE_RET_PROBES - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: bench_ret"); -MODULE_AUTHOR("Martin Hunt"); - -static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} - -static int inst_sys_getgid_ret (struct kretprobe_instance *ri, struct pt_regs *regs) -{ - return 0; -} - -static int inst_sys_getgid (struct kprobe *p, struct pt_regs *regs) -{ - return 0; -} - -static struct kretprobe kpr[] = { - { - .kp.addr = "sys_getuid", - .handler = inst_sys_getuid - }, - { - .kp.addr = "sys_getgid", - .handler = inst_sys_getgid_ret - } -}; - -static struct kprobe kp[] = { - { - .addr = "sys_getgid", - .pre_handler = inst_sys_getgid - } -}; - - -#define NUM_KPROBES (sizeof(kpr)/sizeof(struct kretprobe)) - -int probe_start(void) -{ - int ret = _stp_register_kretprobes (kpr, NUM_KPROBES); - if (ret >= 0) { - if ((ret = _stp_register_kprobes (kp, 1)) < 0) - _stp_unregister_kretprobes (kpr, NUM_KPROBES); - } - return ret; -} - -void probe_exit (void) -{ - _stp_unregister_kretprobes (kpr, NUM_KPROBES); - _stp_unregister_kprobes (kp, 1); -} diff --git a/runtime/probes/bench/build b/runtime/probes/bench/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/bench/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/bench/check_modules b/runtime/probes/bench/check_modules deleted file mode 100755 index c3ab9ac3..00000000 --- a/runtime/probes/bench/check_modules +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -RELAYFS=`grep " relayfs_poll" /boot/System.map-\`uname -r\`` -if [ -z "$RELAYFS" ] -then - RELAYFS=`lsmod | grep relayfs` - if [ -z "$RELAYFS" ] - then - /sbin/insmod ../../relayfs/relayfs.ko - fi -fi - -if [ ! -d "/mnt/relay" ] -then - mkdir /mnt/relay -fi - -MOUNT=`mount | grep relayfs |awk '{print $1}'` -if [ "$MOUNT" != "relayfs" ] -then - mount -t relayfs relayfs /mnt/relay -fi - -STP_CONTROL=`lsmod | grep stp_control |awk '{print $1}'` -if [ "$STP_CONTROL" != "stp_control" ] -then - /sbin/insmod ../../transport/stp-control.ko -fi diff --git a/runtime/probes/bench/itest.c b/runtime/probes/bench/itest.c deleted file mode 100644 index 8ac11b8f..00000000 --- a/runtime/probes/bench/itest.c +++ /dev/null @@ -1,71 +0,0 @@ -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/time.h> -#include <stdlib.h> -#include <sys/resource.h> -#include <unistd.h> - -typedef unsigned long long uint64; -struct rusage rstart; -struct timeval tstart, tstop; -uint64 ttime = 0; - -void start() -{ - gettimeofday (&tstart, NULL); - getrusage (RUSAGE_SELF, &rstart); -} - -uint64 usecs (struct timeval *tv) -{ - return tv->tv_sec * 1000000 + tv->tv_usec; -} - -uint64 stop() -{ - struct rusage rend; - getrusage (RUSAGE_SELF, &rend); - gettimeofday (&tstop, NULL); - uint64 utime = usecs(&rend.ru_utime) - usecs(&rstart.ru_utime); - uint64 stime = usecs(&rend.ru_stime) - usecs(&rstart.ru_stime); - ttime = usecs(&tstop) - usecs(&tstart); - return utime + stime; -} - -void usage(char *name) -{ - printf ("Usage %s [time]\nWhere \"time\" is millions of times to loop.\n", name); - exit(1); -} - -int main(int argc, char *argv[]) -{ - int i, n = 1; - uint64 nsecs; - - if (argc > 2) - usage(argv[0]); - - if (argc == 2) { - n = strtol(argv[1], NULL, 10); - if (n == 0) - usage(argv[0]); - } - - - start(); - for (i = 0; i < n * 1000000; i++) - getuid(); - - nsecs = stop() / (n * 1000); - - /* returns - nanosecs per call (user + system time) - elapsed usecs (real time) - */ - printf("%lld %.2f\n", nsecs, ttime/1000000.0); - - return 0; -} diff --git a/runtime/probes/bench/run_bench b/runtime/probes/bench/run_bench deleted file mode 100755 index a9442d3b..00000000 --- a/runtime/probes/bench/run_bench +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/tclsh -# -*- tcl -*- - -proc do_time {module n} { - global Failures - - # start kprobes - if {[catch {exec ../../stpd/staprun -rmq $module.ko > xxx &} pid]} { - puts $pid - exit -1 - } - - exec sleep 2 - - # get the timings while kprobes running - if {[catch {exec ./ttest $n} res2]} { - puts $res2 - exit -1 - } - - # terminate kprobes - if {[catch {exec kill -s SIGINT $pid} res]} { - puts $res - } - - exec sleep 2 - - # look for warnings - exec tail xxx >xxx.tail - if {[catch {open xxx.tail r} fd]} { - puts "Cannot open test output\n" - exit -1 - } - - set Failures 0 - while {[gets $fd line] >= 0} { - if {[regexp {^\033\[33mWARNING: \033\[0mThere were ([0-9]*) transport failures.} $line match var]} { - set Failures $var - break - } - } - close $fd - exec /bin/rm -f xxx xxx.out - return $res2 -} - -######## START HERE ########### - - -set nproc [exec grep ^processor /proc/cpuinfo | wc -l] -if {![catch {exec grep "physical id" /proc/cpuinfo} phyid]} { - foreach phy [split $phyid \n] { - set cpu($phy) 1 - } -} -set model [exec grep "model name" /proc/cpuinfo] -set model [lindex [split $model \n] 0] -set model [string range $model [expr [string first : $model]+1] end] -set model [string trimleft $model] - -puts "STP BENCH for [exec uname -r] on [exec uname -m]" -if {[file exists /etc/redhat-release]} { - puts [exec cat /etc/redhat-release] -} -puts "[exec uname -n]: [exec uptime]" -if {$nproc > 1} { - puts "processors: $nproc ([array size cpu] physical) $model" -} else { - puts "processors: $nproc $model" -} -set mem [split [exec cat /proc/meminfo] \n] -puts "[lindex $mem 0] [lindex $mem 1]" -puts "--------------------------------------" - -# get the timings without kprobes -if {[catch {exec ./ttest 4} res1]} { - puts $res1 - exit -1 -} - -set r_overhead [lindex $res1 0] -set w_overhead [lindex $res1 1] - -puts "function call overhead = $r_overhead ns" -puts "--------------------------------------" - -set res2 [do_time bench 4] -set t_kprobe [expr [lindex $res2 0] - $r_overhead] -set t_jprobe [expr [lindex $res2 1] - $w_overhead] - -puts "Jprobes overhead = $t_jprobe ns" -puts "Kprobes overhead = $t_kprobe ns" -puts "--------------------------------------" - -if {[file exists bench_ret.ko]} { - set res2 [do_time bench_ret 4] - set t_ret [expr [lindex $res2 0] - $r_overhead] - set t_entret [expr [lindex $res2 1] - $w_overhead] - - puts "Return probe overhead = $t_ret ns" - puts "Entry+Return probe overhead = $t_entret ns" - puts "--------------------------------------" -} - -set res2 [do_time bench_multi 4] -set t_k2 [expr [lindex $res2 0] - $r_overhead] -set t_k4 [expr [lindex $res2 1] - $w_overhead] - -puts "2 kprobes on same func = $t_k2 ns" -puts "4 kprobes on same func = $t_k4 ns" -puts "--------------------------------------" - -set res2 [do_time bench_io1 1] -# subtract function call overhead and kprobe overhead -set t_printf [expr [lindex $res2 0] - $r_overhead - $t_kprobe] -set t_print [expr [lindex $res2 1] - $w_overhead - $t_kprobe] - -puts "PROCFS" -puts "_stp_printf on 100 chars = $t_printf ns." -puts "_stp_print on 100 chars = $t_print ns." -puts "Transport failures: $Failures" -puts "--------------------------------------" -exec sleep 4 - -set res2 [do_time bench_io2 1] -# subtract function call overhead and kprobe overhead -set t_printf [expr [lindex $res2 0] - $r_overhead - $t_kprobe] -set t_print [expr [lindex $res2 1] - $w_overhead - $t_kprobe] - -puts "RELAYFS" -puts "_stp_printf on 100 chars = $t_printf ns." -puts "_stp_print on 100 chars = $t_print ns." -puts "Transport failures: $Failures" -puts "--------------------------------------" - -exec /bin/rm -f stpd_cpu* diff --git a/runtime/probes/bench/targets b/runtime/probes/bench/targets deleted file mode 100644 index 6c89c8d7..00000000 --- a/runtime/probes/bench/targets +++ /dev/null @@ -1,7 +0,0 @@ -bench -bench_io1 -bench_io2 -bench_io3 -bench_io4 -bench_ret -bench_multi diff --git a/runtime/probes/bench/trans_bench b/runtime/probes/bench/trans_bench deleted file mode 100755 index 12adbaff..00000000 --- a/runtime/probes/bench/trans_bench +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/tclsh -# -*- tcl -*- - -proc do_time {module n buf} { - global Failures Filesize - - # start kprobes - if {[catch {exec ../../stpd/staprun -b $buf $module.ko > xxx &} pid]} { - puts $pid - exit -1 - } - - exec sleep 2 - - # get the timings while kprobes running - if {[catch {exec ./itest $n} res2]} { - puts "itest failed: $res2" - exit -1 - } - - exec sleep 4 - # terminate kprobes - if {[catch {exec kill -s SIGINT $pid} res]} { - puts "Kill failed: $res" - } - - exec sleep 4 - - # look for warnings - exec tail xxx >xxx.tail - if {[catch {open xxx.tail r} fd]} { - puts "Cannot open test output\n" - exit -1 - } - - set Failures 0 - while {[gets $fd line] >= 0} { - if {[regexp {^\033\[33mWARNING: \033\[0mThere were ([0-9]*) transport failures.} $line match var]} { - set Failures $var - break - } - } - close $fd - - set Filesize [file size xxx] - exec /bin/rm -f xxx xxx.out - return $res2 -} - -######## START HERE ########### - - -set nproc [exec grep ^processor /proc/cpuinfo | wc -l] -if {![catch {exec grep "physical id" /proc/cpuinfo} phyid]} { - foreach phy [split $phyid \n] { - set cpu($phy) 1 - } -} -set model [exec grep "model name" /proc/cpuinfo] -set model [lindex [split $model \n] 0] -set model [string range $model [expr [string first : $model]+1] end] -set model [string trimleft $model] - -puts "TRANS BENCH for [exec uname -r] on [exec uname -m]" -if {[file exists /etc/redhat-release]} { - puts [exec cat /etc/redhat-release] -} -puts "[exec uname -n]: [exec uptime]" -if {$nproc > 1} { - puts "processors: $nproc ([array size cpu] physical) $model" -} else { - puts "processors: $nproc $model" -} -set mem [split [exec cat /proc/meminfo] \n] -puts "[lindex $mem 0] [lindex $mem 1]" -puts "--------------------------------------" - -# load the modules -if {[catch {exec stp_check} res]} { - puts $res - exit -1 -} - -# warmup -exec ./itest 20 > /dev/null - -set res1 [do_time bench 1 1] -set call_overhead [lindex $res1 0] - -puts "Function call plus kprobe overhead = $call_overhead ns per call" -puts "--------------------------------------" - - -set max 5 -set n 1 -set buf 1 -while {$buf <= 64 && $n < $max} { - set Failures 0 - while {!$Failures && $n < $max} { - set res2 [do_time bench_io1 $n $buf] - set t_printf [expr [lindex $res2 0] - $call_overhead] - set total_print [lindex $res2 1] - puts "PROCFS with ${buf}MB buffers" - puts "_stp_printf on 100 chars = $t_printf ns / call system + user time." - if {$t_printf < 0} { - puts "res2=$res2" - exit - } - puts "_stp_printf of [expr $n * 100]MB in $total_print secs real time." - puts "Transfer rate = [format "%6.2f" [expr ($n * 100)/$total_print]] MB/sec" - puts "Transport failures: $Failures" - if {$Filesize != [expr $n * 100000000]} { - puts "WARNING: file size was $Filesize (expected [expr $n * 100000000])." - } - puts "--------------------------------------" - if {$Failures == 0} {incr n} - } - set buf [expr $buf + $buf] -} - -set max 5 -set n 1 -set buf 1 -while {$buf <= 64 && $n < $max} { - set Failures 0 - while {!$Failures && $n < $max} { - set res2 [do_time bench_io2 $n $buf] - set t_printf [expr [lindex $res2 0] - $call_overhead] - set total_print [lindex $res2 1] - puts "RELAYFS with ${buf}MB buffers" - puts "_stp_printf on 100 chars = $t_printf ns / call system + user time." - if {$t_printf < 0} { - puts "res2=$res2" - exit - } - puts "_stp_printf of [expr $n * 100]MB in $total_print secs real time." - puts "Transfer rate = [format "%6.2f" [expr ($n * 100)/$total_print]] MB/sec" - puts "Transport failures: $Failures" - if {$Filesize != [expr $n * 100000000]} { - puts "WARNING: file size was $Filesize (expected [expr $n * 100000000])." - } - puts "--------------------------------------" - if {$Failures == 0} {incr n} - } - set buf [expr $buf + $buf] -} - -set Failures 0 -set buf 1 -set res2 [do_time bench_io3 1 $buf] -set t_printf [expr [lindex $res2 0] - $call_overhead] -set total_print [lindex $res2 1] -puts "PROCFS with ${buf}MB buffers" -puts "_stp_printf on 1000 chars = $t_printf ns / call system + user time." -if {$t_printf < 0} { - puts "res2=$res2" - exit -} -puts "_stp_printf of 1GB in $total_print secs real time." -puts "Transfer rate = [format "%6.2f" [expr 1000/$total_print]] MB/sec" -puts "Transport failures: $Failures" -if {$Filesize != 1000000000} { - puts "WARNING: file size was $Filesize (expected 1000000000)." -} -puts "--------------------------------------" - -set Failures 0 -set buf 1 -set res2 [do_time bench_io4 1 $buf] -set t_printf [expr [lindex $res2 0] - $call_overhead] -set total_print [lindex $res2 1] -puts "RELAYFS with ${buf}MB buffers" -puts "_stp_printf on 1000 chars = $t_printf ns / call system + user time." -if {$t_printf < 0} { - puts "res2=$res2" - exit -} -puts "_stp_printf of 1GB in $total_print secs real time." -puts "Transfer rate = [format "%6.2f" [expr 1000/$total_print]] MB/sec" -puts "Transport failures: $Failures" -if {$Filesize != 1000000000} { - puts "WARNING: file size was $Filesize (expected 1000000000)." -} -puts "--------------------------------------" - -exec /bin/rm -f stpd_cpu* diff --git a/runtime/probes/bench/ttest.c b/runtime/probes/bench/ttest.c deleted file mode 100644 index 93b37c84..00000000 --- a/runtime/probes/bench/ttest.c +++ /dev/null @@ -1,74 +0,0 @@ -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/time.h> -#include <stdlib.h> -#include <sys/resource.h> -#include <unistd.h> - -typedef unsigned long long uint64; -struct rusage rstart; - -void start() -{ - getrusage (RUSAGE_SELF, &rstart); -} - -uint64 usecs (struct timeval *tv) -{ - return tv->tv_sec * 1000000 + tv->tv_usec; -} - -uint64 stop() -{ - struct rusage rend; - getrusage (RUSAGE_SELF, &rend); - uint64 utime = usecs(&rend.ru_utime) - usecs(&rstart.ru_utime); - uint64 stime = usecs(&rend.ru_stime) - usecs(&rstart.ru_stime); - return utime + stime; -} - -void usage(char *name) -{ - printf ("Usage %s [time]\nWhere \"time\" is millions of times to loop.\n", name); - exit(1); -} - -int main(int argc, char *argv[]) -{ - int i, n = 1; - uint64 nsecs; - - if (argc > 2) - usage(argv[0]); - - if (argc == 2) { - n = strtol(argv[1], NULL, 10); - if (n == 0) - usage(argv[0]); - } - - /* large warmup time */ - for (i = 0; i < n * 1000000; i++) { - getuid(); - } - - start(); - for (i = 0; i < n * 1000000; i++) - getuid(); - - nsecs = stop() / (n * 1000); - - printf("%lld ", nsecs); - - start(); - for (i = 0; i < n * 1000000; i++) - getgid(); - - nsecs = stop() / (n * 1000); - - printf("%lld\n", nsecs); - - return 0; -} diff --git a/runtime/probes/build b/runtime/probes/build deleted file mode 100755 index ad65b0dc..00000000 --- a/runtime/probes/build +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/tclsh -# -*- tcl -*- - -# simple script to build each probe directory - -proc usage {} { - puts "Usage: build \[-v\] \[clean\] \[debug\]" - exit -} - -set clean "" -set verbose "" -set debug "" - -foreach arg $argv { - if {$arg == "clean"} { - set clean $arg - } elseif {$arg == "-v"} { - set verbose $arg - } elseif {$arg == "debug"} { - set debug $arg - } else { - usage - } -} - -set cmd "exec ../build_probe $verbose $clean" - -foreach filename [lsort [glob *]] { - if {$filename != "CVS" && [file isdirectory $filename]} { - cd $filename - if {[catch {exec ../build_probe $verbose $clean $debug} res]} { - puts $res - exit - } - puts $res - cd .. - } -} - diff --git a/runtime/probes/build_probe b/runtime/probes/build_probe deleted file mode 100755 index 7e3207b1..00000000 --- a/runtime/probes/build_probe +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/tclsh -# -*- tcl -*- - -proc usage {} { - puts "Usage: build \[-v\] \[clean\]" - exit -1 -} - -# use Makefile.template to generate a Makefile -proc create_makefile {target relayfs} { - if {[catch {open ../Makefile.template r} fd]} { - puts "ERROR opening ../Makefile.template" - exit -1 - } - if {[catch {open Makefile w} mfd]} { - puts "ERROR creating Makefile" - exit -1 - } - while {[gets $fd line] >= 0} { - if {[regsub XXX $line $target newline]} { - set line $newline - } - if {[regsub RELAYFS $line $relayfs newline]} { - set line $newline - } - puts $mfd $line - } - close $fd - close $mfd -} - -proc build {{target ""}} { - global clean verbose debug - if {$target == ""} { - set target [file tail [pwd]] - } - if {$clean} { - puts "Cleaning $target" - if {[catch {exec make clean >& compile.errors} res]} { - [exec cat compile.errors] - exit -1 - } - } else { - puts "Building $target" - - if {$debug == ""} { - if {[catch {exec make >& compile.errors} res]} { - puts "\n------------ Compile error in $target -------------------\n" - if {[catch {open compile.errors r} fd]} { - puts "Compile failed for unknown reasons" - exit -1 - } - while {[gets $fd line] >= 0} { - puts $line - } - close $fd - exit -1 - } - } else { - if {[catch {exec make debug >& compile.errors} res]} { - puts "\n------------ Compile error in $target -------------------\n" - if {[catch {open compile.errors r} fd]} { - puts "Compile failed for unknown reasons" - exit -1 - } - while {[gets $fd line] >= 0} { - puts $line - } - close $fd - exit -1 - } - } - - if {![catch {open compile.errors r} fd]} { - # search for warnings - set bad 0 - while {[gets $fd line] >= 0} { - if {$verbose} { - puts $line - } else { - if {[regexp {[^W]*([A-Za-z][A-Za-z0-9_]*)[^\"]*\"([^\"]*)} $line match warn var]} { - if {$warn == "Warning"} { - switch $var { - _stp_ctrl_unregister - - _stp_ctrl_register - - relay_subbufs_consumed - - _stp_ctrl_send - - relay_open - - relayfs_create_dir - - relayfs_remove_dir - - relay_flush - - relay_switch_subbuf - - relay_close {} - default { - if {$bad == 0} { - puts "\n------------ Unexpected Warnings in $target -------------------\n" - } - puts $line - set bad 1 - } - } - } - } - } - } - close $fd - } - if {$bad} { - exit -1 - } - } -} - -set clean 0 -set verbose 0 -set debug "" -foreach arg $argv { - if {$arg == "clean"} { - set clean 1 - } elseif {$arg == "-v"} { - set verbose 1 - } elseif {$arg == "debug"} { - set debug $arg - } elseif {$arg != ""} { - usage - } -} - -set relayfs "" -if {![file exists /lib/modules/[exec uname -r]/build/include/linux/relayfs_fs.h]} { - set relayfs {-I $(RT)/relayfs} -} - -if {![catch {open targets r} tfd]} { - while {[gets $tfd line] >= 0} { - set target [lindex $line 0] - create_makefile $target $relayfs - build $target - catch {exec /bin/rm Makefile} - } - close $tfd -} else { - if {![file exists Makefile]} { - puts "Now in [pwd]" - puts "ERROR: No targets file found and no Makefile either" - exit -1 - } - build -} - -puts "Done" -catch {exec /bin/rm compile.errors} - - diff --git a/runtime/probes/os_timer/build b/runtime/probes/os_timer/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/os_timer/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/os_timer/os_timer.c b/runtime/probes/os_timer/os_timer.c deleted file mode 100644 index 4a80d02b..00000000 --- a/runtime/probes/os_timer/os_timer.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Use the os timer as a poor-man's time based profiler for a UP system */ - -/* Demonstrates the beginnings of a generic framework for */ -/* asynchronous probes using the runtime */ - -/* @todo NOTE: the statement: regs = task_pt_regs(current); */ -/* isn't working in the way I would expect. The timer callback */ -/* happens, but I don't get a reasonable value in regs->eip */ -/* Can this routine be called during the timer callback? */ - -/* os includes */ -#include "linux/timer.h" - -/* How many strings to allocate. see strings.c. Default is 0. */ -#define STP_NUM_STRINGS 1 - -/* maximum size for a string. default is 2048 */ -#define STP_STRING_SIZE 2048 - -/* size of strings saved in maps */ -#define MAP_STRING_LENGTH 256 - -/* width of histograms. Default 50 */ -#define HIST_WIDTH 50 - -/* always include this. Put all non-map defines above it. */ -#include "runtime.h" - -/* @todo since we don't have aggregation maps yet, try regular maps */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#define KEY2_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -#include "stat.c" -#include "stack.c" - -MODULE_DESCRIPTION("SystemTap probe: os_timer"); -MODULE_AUTHOR("Charles Spirakis <charles.spirakis@intel.com>"); - -Stat timing; -MAP cur_addr; - -/* A generic asynchorous probe entry point */ -void inst_async(struct pt_regs *regs) -{ - u64 start; - u64 end; - unsigned long ip; - - rdtscll(start); - ip = REG_IP(regs); - - /* Create a map of interrupted addresses seen */ - /* really want a map of image name / address */ - _stp_map_add_sii(cur_addr, current->comm, ip, 1); - - /* Need _stp_stack() and _stp_ustack()? */ - /* _stp_image() and aggregation maps */ - - rdtscll(end); - _stp_stat_add(timing, end - start); -} - -static struct timer_list timer; - -/* Helper function to convert from os timer callback into */ -/* generic asynchronous entry point form */ -static void os_timer_callback(unsigned long val) -{ - struct pt_regs *regs; - - /* setup the next timeout now so it doesn't drift */ - /* due to processing the async probe code */ - mod_timer(&timer, jiffies + val); - - /* determine pt_regs from the kernel stack */ - /* @todo This doesn't seem to get a reasonable pt_regs pointer */ - /* based on the value of regs->eip. However, KSTK_EIP() in */ - /* include/asm/processor.h implies regs->eip is valid... */ - regs = task_pt_regs(current); - - /* Call the asynchronous probe with a ptregs struct */ - inst_async(regs); -} - -/* called when the module loads. */ -int probe_start(void) -{ - timing = _stp_stat_init(HIST_LINEAR, 0, 5000, 250); - - cur_addr = _stp_map_new_sii(1000); - - /* register the os_timer */ - init_timer(&timer); - - timer.expires = jiffies + 50; - timer.function = os_timer_callback; - - /* data is usd for defining when the next timeout shoud occur */ - timer.data = 50; - - add_timer(&timer); - return 0; -} - -void probe_exit (void) -{ - /* unregister the os_timer */ - del_timer_sync(&timer); - - /* print out any colledted data, etc */ - _stp_printf ("os timer done.\n"); - _stp_printf ("WARNING: Currently using task_pt_regs() to get the pt_regs struct\n"); - _stp_printf ("during the timer interrupt, but there seems to be issues with that...\n\n"); - _stp_stat_print (timing, "timing (cpu cycles): # calls:%C avg:%A min:%m max:%M\n%H", 0); - - _stp_print("Process\tIp\tCount\n"); - _stp_map_print (cur_addr, "%1s\t%2P\t%d"); - _stp_map_del(cur_addr); - - _stp_print_flush(); -} - diff --git a/runtime/probes/os_timer/stp b/runtime/probes/os_timer/stp deleted file mode 100755 index f3feee70..00000000 --- a/runtime/probes/os_timer/stp +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -source ../stp diff --git a/runtime/probes/os_timer/targets b/runtime/probes/os_timer/targets deleted file mode 100644 index 879d3afc..00000000 --- a/runtime/probes/os_timer/targets +++ /dev/null @@ -1 +0,0 @@ -os_timer diff --git a/runtime/probes/scf/README b/runtime/probes/scf/README deleted file mode 100644 index 39fcfda8..00000000 --- a/runtime/probes/scf/README +++ /dev/null @@ -1,12 +0,0 @@ -/** @dir scf -This example probe instruments smp_call_function(). - -It demonstrates using stack backtraces as map keys to compute the most -common path to a function. - -kernel.function("smp_call_function") -{ - traces[stack()] += 1 -} - -*/ diff --git a/runtime/probes/scf/build b/runtime/probes/scf/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/scf/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/scf/scf.c b/runtime/probes/scf/scf.c deleted file mode 100644 index 0e29df43..00000000 --- a/runtime/probes/scf/scf.c +++ /dev/null @@ -1,50 +0,0 @@ -#define STP_NUM_STRINGS 1 -#include "runtime.h" - -#define MAP_STRING_LENGTH 512 - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#include "map-gen.c" - -#include "map.c" -#include "sym.c" -#include "current.c" -#include "stack.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: scf"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - -MAP map1; - -int inst_smp_call_function (struct kprobe *p, struct pt_regs *regs) -{ - String str = _stp_string_init (0); - _stp_stack_sprint (str, regs, 1); - _stp_map_add_si (map1, _stp_string_ptr(str), 1); - return 0; -} - -static struct kprobe stp_probes[] = { - { - .addr = (kprobe_opcode_t *)"smp_call_function", - .pre_handler = inst_smp_call_function - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct kprobe)) - -int probe_start(void) -{ - map1 = _stp_map_new_si (100); - return _stp_register_kprobes (stp_probes, MAX_STP_ROUTINE); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (stp_probes, MAX_STP_ROUTINE); - _stp_map_print (map1, "trace[%1s] = %d\n"); - _stp_map_del (map1); -} - diff --git a/runtime/probes/scf/targets b/runtime/probes/scf/targets deleted file mode 100644 index aafcca22..00000000 --- a/runtime/probes/scf/targets +++ /dev/null @@ -1 +0,0 @@ -scf diff --git a/runtime/probes/shellsnoop/README b/runtime/probes/shellsnoop/README deleted file mode 100644 index 70b5e614..00000000 --- a/runtime/probes/shellsnoop/README +++ /dev/null @@ -1,73 +0,0 @@ -/** @dir shellsnoop -Snoops on what commands are being run by shells. - -This is a translation of on an old dtr probe. It demonstrates maps, -lists, and how to use _stp_copy_argv_from_user() and _stp_strncpy_from_user(). - -Original dtr source: - -\verbatim -# shellsnoop.probe - snoop shell execution as it occurs. -# clone of dtrace shellsnoop example - -global { - long @pids[long]; -} - -probe do_execve:entry { - char __user *vstr; - char str[256]; - int len; - - /* watch shells only */ - /* FIXME: detect more shells, like csh, tcsh, zsh */ - - if (!strcmp(current->comm,"bash") || !strcmp(current->comm,"sh") || !strcmp(current->comm, "zsh") - || !strcmp(current->comm, "tcsh") || !strcmp(current->comm, "pdksh")) - { - dlog ("%d\t%d\t%d\t%s ", current->uid, current->pid, current->parent->pid, filename); - @pids[current->pid] = 1; - - /* print out argv, ignoring argv[0] */ - if (argv) argv++; - while (argv != NULL) - { - if (get_user (vstr, argv)) - break; - if (!vstr) - break; - len = dtr_strncpy_from_user(str, vstr, 256); - str[len] = 0; - printk ("%s ", str); - argv++; - } - printk ("\n"); - } -} - -# use filp_open because copy_from_user not needed there -probe filp_open:entry { - if (@pids[current->pid]) - dlog ("%d\t%d\t%s\tO %s\n", current->pid, current->parent->pid, current->comm, filename); -} - -probe sys_read:entry { - if (@pids[current->pid]) - dlog ("%d\t%d\t%s\tR %d\n", current->pid, current->parent->pid, current->comm, fd); -} - -probe sys_write:entry { - size_t len; - char str[256]; - if (@pids[current->pid]) - { - if (count < 64) len = count; - else len = 64; - if (len = dtr_strncpy_from_user(str, buf, len)) { - str[len] = 0; - dlog ("%d\t%d\t%s\tW %s\n", current->pid, current->parent->pid, current->comm, str); - } - } -} -\endverbatim -*/ diff --git a/runtime/probes/shellsnoop/build b/runtime/probes/shellsnoop/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/shellsnoop/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/shellsnoop/shellsnoop.c b/runtime/probes/shellsnoop/shellsnoop.c deleted file mode 100644 index dd0c81b9..00000000 --- a/runtime/probes/shellsnoop/shellsnoop.c +++ /dev/null @@ -1,161 +0,0 @@ -//#define STP_RELAYFS -#define STP_NUM_STRINGS 1 -#define STP_STRING_SIZE 8192 -#include "runtime.h" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" -#include "copy.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: shellsnoop"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - -MAP pids, arglist ; - -void _stp_copy_argv_from_user (MAP list, char __user *__user *argv) -{ - char str[128]; - char __user *vstr; - int len, i = 0; - - if (argv) - argv++; - - while (argv != NULL) { - if (get_user (vstr, argv)) - break; - - if (vstr == NULL) - break; - - len = _stp_strncpy_from_user(str, vstr, 128); - str[len] = 0; - _stp_map_set_is (list, i++, str); - argv++; - } -} - -int inst_do_execve (char * filename, char __user *__user *argv, char __user *__user *envp, struct pt_regs * regs) -{ - struct map_node *ptr; - - /* watch shells only */ - /* FIXME: detect more shells, like csh, tcsh, zsh */ - - if (!strcmp(current->comm,"bash") || !strcmp(current->comm,"sh") || !strcmp(current->comm, "zsh") - || !strcmp(current->comm, "tcsh") || !strcmp(current->comm, "pdksh")) - { - _stp_printf ("%d\t%d\t%d\t%s ", current->uid, current->pid, current->parent->pid, filename); - - _stp_map_set_ii (pids, current->pid, 1); - - _stp_map_clear (arglist); - _stp_copy_argv_from_user (arglist, argv); - - foreach (arglist, ptr) - _stp_printf ("%s ", _stp_get_str(ptr)); - _stp_print("\n"); - - _stp_print_flush(); - } - jprobe_return(); - return 0; -} - -struct file * inst_filp_open (const char * filename, int flags, int mode) -{ - if (_stp_map_get_ii (pids, current->pid)) { - _stp_printf ("%d\t%d\t%s\tO %s\n", current->pid, current->parent->pid, current->comm, filename); - _stp_print_flush(); - } - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_read (unsigned int fd, char __user * buf, size_t count) -{ - if (_stp_map_get_ii (pids, current->pid)) { - _stp_printf ("%d\t%d\t%s\tR %d\n", current->pid, current->parent->pid, current->comm, fd); - _stp_print_flush(); - } - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_write (unsigned int fd, const char __user * buf, size_t count) -{ - if (_stp_map_get_ii (pids, current->pid)) { - String str = _stp_string_init (0); - _stp_string_from_user(str, buf, count); - _stp_printf ("%d\t%d\t%s\tW %s", current->pid, current->parent->pid, - current->comm, _stp_string_ptr(str)); - _stp_print_flush(); - } - - jprobe_return(); - return 0; -} - -static struct jprobe stp_probes[] = { - { - .kp.addr = (kprobe_opcode_t *)"do_execve", - .entry = (kprobe_opcode_t *) inst_do_execve - }, - { - .kp.addr = (kprobe_opcode_t *)"filp_open", - .entry = (kprobe_opcode_t *) inst_filp_open - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_read", - .entry = (kprobe_opcode_t *) inst_sys_read - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_write", - .entry = (kprobe_opcode_t *) inst_sys_write - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct jprobe)) - - -int probe_start(void) -{ - int ret; - - /* now initialize any data or variables */ - pids = _stp_map_new_ii(10000); - arglist = _stp_map_new_is (10); - - /* now we are ready to enable the probes */ - ret = _stp_register_jprobes (stp_probes, MAX_STP_ROUTINE); - - if (ret < 0) { - _stp_map_del (pids); - _stp_map_del (arglist); - return ret; - } - - _stp_printf("instrumentation is enabled... %s\n", __this_module.name); - _stp_print_flush(); - return ret; -} - - -void probe_exit (void) -{ - _stp_unregister_jprobes (stp_probes, MAX_STP_ROUTINE); - _stp_map_del (pids); - _stp_map_del (arglist); - _stp_printf("\nDropped %d packets\n", atomic_read(&_stp_transport_failures)); - _stp_print_flush(); -} - - diff --git a/runtime/probes/shellsnoop/targets b/runtime/probes/shellsnoop/targets deleted file mode 100644 index fdd0d724..00000000 --- a/runtime/probes/shellsnoop/targets +++ /dev/null @@ -1 +0,0 @@ -shellsnoop diff --git a/runtime/probes/tasklet/README b/runtime/probes/tasklet/README deleted file mode 100644 index 8507ad9b..00000000 --- a/runtime/probes/tasklet/README +++ /dev/null @@ -1,9 +0,0 @@ -/** @dir tasklet -Sample probe in a tasklet. Useful for interrupt context testing. - -\verbatim -> make -> ./stp stp_tasklet.ko -\endverbatim - -*/ diff --git a/runtime/probes/tasklet/build b/runtime/probes/tasklet/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/tasklet/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/tasklet/stp_tasklet.c b/runtime/probes/tasklet/stp_tasklet.c deleted file mode 100644 index f47fea9e..00000000 --- a/runtime/probes/tasklet/stp_tasklet.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Framework for putting a jprobe in a tasklet. */ -/* Useful for testing probes in interrupt context. */ -/* Doesn't do anything useful as is. Put test code in the inst func */ - -#define STP_NETLINK_ONLY -#define STP_NUM_STRINGS 1 - -#include "runtime.h" -#include "probes.c" - -MODULE_DESCRIPTION("test jprobes of tasklets"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - -void inst__rcu_process_callbacks(struct rcu_ctrlblk *rcp, - struct rcu_state *rsp, struct rcu_data *rdp) -{ - _stp_printf ("count=%d irqs_disabled=%d in_interrupt=%d in_irq=%d", - preempt_count(), irqs_disabled(), in_interrupt(), in_irq()); - _stp_print_flush(); - jprobe_return(); -} - -static struct jprobe stp_probes[] = { - { - .kp.addr = (kprobe_opcode_t *)"__rcu_process_callbacks", - .entry = (kprobe_opcode_t *) inst__rcu_process_callbacks - }, -}; -#define MAX_STP_PROBES (sizeof(stp_probes)/sizeof(struct jprobe)) - -int probe_start(void) -{ - return _stp_register_jprobes (stp_probes, MAX_STP_PROBES); -} - -void probe_exit (void) -{ - _stp_unregister_jprobes (stp_probes, MAX_STP_PROBES); -} - diff --git a/runtime/probes/tasklet/targets b/runtime/probes/tasklet/targets deleted file mode 100644 index 236dbd95..00000000 --- a/runtime/probes/tasklet/targets +++ /dev/null @@ -1 +0,0 @@ -stp_tasklet diff --git a/runtime/probes/test4/README b/runtime/probes/test4/README deleted file mode 100644 index 75d4be10..00000000 --- a/runtime/probes/test4/README +++ /dev/null @@ -1,24 +0,0 @@ -/** @dir test4 -This example probe tracks file opens, reads and writes. -It demonstrates maps, stats, and iterators. - -This is a translation of on an old dtr probe. Original source is -\verbatim -global { - long @opens[string]; - sum @reads[string], @writes[string]; -} - -probe sys_open:entry { - @opens[current->comm]++; -} - -probe sys_read:entry { - @reads[current->comm] << count; -} - -probe sys_write:entry { - @writes[current->comm] << count; -} -\endverbatim -*/ diff --git a/runtime/probes/test4/build b/runtime/probes/test4/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/test4/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/test4/targets b/runtime/probes/test4/targets deleted file mode 100644 index d234c5e0..00000000 --- a/runtime/probes/test4/targets +++ /dev/null @@ -1 +0,0 @@ -test4 diff --git a/runtime/probes/test4/test4.c b/runtime/probes/test4/test4.c deleted file mode 100644 index 56027186..00000000 --- a/runtime/probes/test4/test4.c +++ /dev/null @@ -1,79 +0,0 @@ -#define STP_NUM_STRINGS 1 -#include "runtime.h" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#include "map-gen.c" - -#define VALUE_TYPE STAT -#define KEY1_TYPE STRING -#include "map-gen.c" - -#include "map.c" -#include "probes.c" - -MODULE_DESCRIPTION("SystemTap probe: test4"); -MODULE_AUTHOR("Martin Hunt <hunt@redhat.com>"); - - -MAP opens, reads, writes; - -asmlinkage long inst_sys_open (const char __user * filename, int flags, int mode) -{ - _stp_map_add_si (opens, current->comm, 1); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_read (unsigned int fd, char __user * buf, size_t count) -{ - _stp_map_add_sx (reads, current->comm, count); - jprobe_return(); - return 0; -} - -asmlinkage ssize_t inst_sys_write (unsigned int fd, const char __user * buf, size_t count) -{ - _stp_map_add_sx (writes, current->comm, count); - jprobe_return(); - return 0; -} - -static struct jprobe stp_probes[] = { - { - .kp.addr = (kprobe_opcode_t *)"sys_open", - .entry = (kprobe_opcode_t *) inst_sys_open - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_read", - .entry = (kprobe_opcode_t *) inst_sys_read - }, - { - .kp.addr = (kprobe_opcode_t *)"sys_write", - .entry = (kprobe_opcode_t *) inst_sys_write - }, -}; - -#define MAX_STP_ROUTINE (sizeof(stp_probes)/sizeof(struct jprobe)) - -int probe_start(void) -{ - opens = _stp_map_new_si (1000); - reads = _stp_map_new_sx (1000, HIST_LOG, 12); - writes = _stp_map_new_sx (1000, HIST_LOG, 12); - return _stp_register_jprobes (stp_probes, MAX_STP_ROUTINE); -} - -void probe_exit (void) -{ - _stp_unregister_jprobes (stp_probes, MAX_STP_ROUTINE); - - _stp_map_print (opens,"%d opens by process \"%1s\""); - _stp_map_print (reads,"reads by process \"%1s\": %C. Total bytes=%S. Average: %A\n%H"); - _stp_map_print (writes,"writes by process \"%1s\": %C. Total bytes=%S. Average: %A\n%H"); - _stp_printf("\nDropped %d packets\n", atomic_read(&_stp_transport_failures)); - _stp_print_flush(); - _stp_map_del (opens); - _stp_map_del (reads); - _stp_map_del (writes); -} diff --git a/runtime/probes/where_func/README b/runtime/probes/where_func/README deleted file mode 100644 index 78009566..00000000 --- a/runtime/probes/where_func/README +++ /dev/null @@ -1,29 +0,0 @@ -/** @dir where_func -This is a silly little instrumentation routine to instrument functions -entry by name. It makes use of the SystemTap runtime libraries to break -down the number of times the function by caller. - -It demonstrates kprobes, passing a module parameter, using the print buffer, -and using _stp_print_symbol() to map the addresses back to locations -in functions. - -By default it instruments schedule(). - -The instrumentation module is built by having the kernel that is going -to be instrumented currently on the machine and doing -\code -./build -\endcode -The instrumentation is inserted as root with: -\code -/sbin/insmod kprobe_funct_where.ko funct_name=function_name -\endcode -The instrumentation is removed as root with: -\code -/sbin/rmmod kprobe_funct_where -\endcode --Will Cohen - -Note that this module is broken now because we don't pass the module parameter -tp staprun. FIXME -*/ diff --git a/runtime/probes/where_func/build b/runtime/probes/where_func/build deleted file mode 100755 index f3e83244..00000000 --- a/runtime/probes/where_func/build +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -../build_probe $* diff --git a/runtime/probes/where_func/kprobe_where_funct.c b/runtime/probes/where_func/kprobe_where_funct.c deleted file mode 100644 index 680dabd8..00000000 --- a/runtime/probes/where_func/kprobe_where_funct.c +++ /dev/null @@ -1,62 +0,0 @@ -/* kprobe_where_funct.c - this is a simple module to get information about calls to a function - that is passed as a module option - Will Cohen -*/ - -#define STP_NUM_STRINGS 1 - -#include "runtime.h" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" -#include "probes.c" -#include "sym.c" -#include "current.c" - -MODULE_DESCRIPTION("SystemTap probe: where_func"); -MODULE_AUTHOR("Will Cohen and Martin Hunt"); - -static char default_name[] = "schedule"; -static char *funct_name = default_name; -module_param(funct_name, charp, 0); -MODULE_PARM_DESC(funct_name, "function entry name.\n"); - -MAP funct_locations; - -static int inst_funct(struct kprobe *p, struct pt_regs *regs) -{ - long ret_addr = _stp_ret_addr(regs); - _stp_map_add_ii(funct_locations, ret_addr, 1); - return 0; -} - -/*For each probe you need to allocate a kprobe structure*/ -static struct kprobe kp[] = { - { - .addr = default_name, - .pre_handler = inst_funct, - } -}; -#define MAX_KPROBES (sizeof(kp)/sizeof(struct kprobe)) - -int probe_start(void) -{ - funct_locations = _stp_map_new_ii (1000); - - if (funct_name) - kp[0].addr = funct_name; - - return _stp_register_kprobes (kp, MAX_KPROBES); -} - -void probe_exit (void) -{ - _stp_unregister_kprobes (kp, MAX_KPROBES); - - _stp_map_print (funct_locations, "Count: %d\tCaller: %1P"); - _stp_map_del(funct_locations); -} diff --git a/runtime/probes/where_func/targets b/runtime/probes/where_func/targets deleted file mode 100644 index 7e8e4cf1..00000000 --- a/runtime/probes/where_func/targets +++ /dev/null @@ -1 +0,0 @@ -kprobe_where_funct diff --git a/runtime/regs.c b/runtime/regs.c index 5821f7e7..81b865b1 100644 --- a/runtime/regs.c +++ b/runtime/regs.c @@ -256,6 +256,13 @@ void _stp_print_regs(struct pt_regs * regs) #elif defined (__powerpc64__) +static int _stp_probing_32bit_app(struct pt_regs *regs) +{ + if (!regs) + return 0; + return (user_mode(regs) && test_tsk_thread_flag(current, TIF_32BIT)); +} + void _stp_print_regs(struct pt_regs * regs) { int i; diff --git a/runtime/regs.h b/runtime/regs.h index 4954020f..123d7601 100644 --- a/runtime/regs.h +++ b/runtime/regs.h @@ -14,7 +14,7 @@ #if defined (STAPCONF_X86_UNIREGS) && (defined (__x86_64__) || defined (__i386__)) #define REG_IP(regs) regs->ip #define REG_SP(regs) regs->sp -#define REG_FP(regs) regs->bp; +#define REG_FP(regs) regs->bp #elif defined (__x86_64__) @@ -25,7 +25,7 @@ #define REG_IP(regs) regs->eip #define REG_SP(regs) regs->esp -#define REG_FP(regs) regs->ebp; +#define REG_FP(regs) regs->ebp #elif defined (__ia64__) #define REG_IP(regs) ((regs)->cr_iip +ia64_psr(regs)->ri) diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index 969c299d..27f4d8c8 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,8 @@ +2008-06-03 Frank Ch. Eigler <fche@elastic.org> + + PR 6429. + * mainloop.c (stp_main_loop): Remove STP_UNWIND message support. + 2008-05-05 Martin Hunt <hunt@redhat.com> * mainloop.c (child_proc): Handle sig_chld diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 61963743..2bbadbc9 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -387,18 +387,6 @@ int stp_main_loop(void) cleanup_and_exit(1); break; } - case STP_UNWIND: - { - int len; - char *ptr = (char *)data; - while (nb > 0) { - send_unwind_data(ptr); - len = strlen(ptr) + 1; - ptr += len; - nb -= len; - } - break; - } default: err("WARNING: ignored message of type %d\n", (type)); } diff --git a/runtime/staprun/unwind_data.c b/runtime/staprun/unwind_data.c deleted file mode 100644 index ed27cc20..00000000 --- a/runtime/staprun/unwind_data.c +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- linux-c -*- - * Unwind data functions for staprun. - * - * 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. - */ - -#include "staprun.h" -#include <elfutils/libdwfl.h> -#include <dwarf.h> - -static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug"; -static char *debuginfo_path = debuginfo_path_arr; -static const Dwfl_Callbacks kernel_callbacks = { - .find_debuginfo = dwfl_standard_find_debuginfo, - .debuginfo_path = &debuginfo_path, - .find_elf = dwfl_linux_kernel_find_elf, - .section_address = dwfl_linux_kernel_module_section_address, -}; - -void *get_module_unwind_data(Dwfl * dwfl, const char *name, int *len) -{ - Dwarf_Addr bias = 0; - Dwarf *dw; - GElf_Ehdr *ehdr, ehdr_mem; - GElf_Shdr *shdr, shdr_mem; - Elf_Scn *scn = NULL; - Elf_Data *data = NULL; - - Dwfl_Module *mod = dwfl_report_module(dwfl, name, 0, 0); - dwfl_report_end(dwfl, NULL, NULL); - dw = dwfl_module_getdwarf(mod, &bias); - Elf *elf = dwarf_getelf(dw); - ehdr = gelf_getehdr(elf, &ehdr_mem); - while ((scn = elf_nextscn(elf, scn))) { - shdr = gelf_getshdr(scn, &shdr_mem); - if (strcmp(elf_strptr(elf, ehdr->e_shstrndx, shdr->sh_name), ".debug_frame") == 0) { - data = elf_rawdata(scn, NULL); - break; - } - } - - if (data == NULL) { - *len = 0; - dbug(2, "module %s returns NULL\n", name); - return NULL; - } - dbug(2, "module %s returns %d\n", name, (int)data->d_size); - *len = data->d_size; - return data->d_buf; -} - -void send_unwind_data(const char *name) -{ - struct _stp_msg_unwind *un; - int unwind_data_len = 0; - void *unwind_data = NULL; - char *buf; - - dbug(2, "module %s\n", name); - if (strcmp(name, "*")) { - Dwfl *dwfl = dwfl_begin(&kernel_callbacks); - - if (name[0] == 0) - unwind_data = get_module_unwind_data(dwfl, "kernel", &unwind_data_len); - else - unwind_data = get_module_unwind_data(dwfl, name, &unwind_data_len); - - /* yuck */ - buf = (char *)malloc(unwind_data_len + sizeof(*un) + sizeof(uint32_t)); - if (!buf) { - err("malloc failed\n"); - return; - } - memcpy(buf + sizeof(*un) + sizeof(uint32_t), unwind_data, unwind_data_len); - dwfl_end(dwfl); - } else { - buf = (char *)malloc(sizeof(*un) + sizeof(uint32_t)); - if (!buf) { - err("malloc failed\n"); - return; - } - } - - un = (struct _stp_msg_unwind *)(buf + sizeof(uint32_t)); - strncpy(un->name, name, sizeof(un->name)); - un->unwind_len = unwind_data_len; - *(uint32_t *) buf = STP_UNWIND; - - /* send unwind data */ - if (write(control_channel, buf, unwind_data_len + sizeof(*un) + sizeof(uint32_t)) <= 0) - err("write failed\n"); -} diff --git a/runtime/stat-common.c b/runtime/stat-common.c index a62297bf..7dabe708 100644 --- a/runtime/stat-common.c +++ b/runtime/stat-common.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * common stats functions for aggragations and maps - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005, 2006, 2007, 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 @@ -299,39 +299,6 @@ static void _stp_stat_print_histogram (Hist st, stat *sd) _stp_print_flush(); } -static void _stp_stat_print_valtype (char *fmt, Hist st, stat *sd, int cpu) -{ - switch (*fmt) { - case 'C': - _stp_printf("%lld", sd->count); - break; - case 'm': - _stp_printf("%lld", sd->min); - break; - case 'M': - _stp_printf("%lld", sd->max); - break; - case 'S': - _stp_printf("%lld", sd->sum); - break; - case 'A': - { - int64_t avg = 0; - if (sd->count) - avg = _stp_div64 (NULL, sd->sum, sd->count); - _stp_printf("%lld", avg); - break; - } - case 'H': - _stp_stat_print_histogram (st, sd); - _stp_print_flush(); - break; - case 'c': - _stp_printf("%d", cpu); - break; - } -} - static void __stp_stat_add (Hist st, stat *sd, int64_t val) { int n; diff --git a/runtime/stat.c b/runtime/stat.c index f8b5f018..8bd7bf12 100644 --- a/runtime/stat.c +++ b/runtime/stat.c @@ -237,56 +237,6 @@ stat *_stp_stat_get (Stat st, int clear) } -static void __stp_stat_print (char *fmt, Stat st, stat *sd, int cpu) -{ - int num; - char *f = (char *)fmt; - while (*f) { - f = next_fmt (f, &num); - _stp_stat_print_valtype (f, &st->hist, sd, cpu); - if (*f) - f++; - } - _stp_print_char('\n'); - _stp_print_flush(); -} - -/** Print per-cpu Stats. - * Prints the Stats for each CPU. - * - * @param st Stat - * @param fmt @ref format_string - * @param clear Set if you want the data cleared after the read. Useful - * for polling. - */ -void _stp_stat_print_cpu (Stat st, char *fmt, int clear) -{ - int i; - for_each_cpu(i) { - stat *sd = per_cpu_ptr (st->sd, i); - STAT_LOCK(sd); - __stp_stat_print (fmt, st, sd, i); - if (clear) - _stp_stat_clear_data (st, sd); - STAT_UNLOCK(sd); - } -} - -/** Print Stats. - * Prints the Stats. - * - * @param st Stat - * @param fmt @ref format_string - * @param clear Set if you want the data cleared after the read. Useful - * for polling. - */ -void _stp_stat_print (Stat st, char *fmt, int clear) -{ - stat *agg = _stp_stat_get(st, clear); - __stp_stat_print (fmt, st, agg, 0); - STAT_UNLOCK(agg); -} - /** Clear Stats. * Clears the Stats. * diff --git a/runtime/syscall.h b/runtime/syscall.h new file mode 100644 index 00000000..36fed2ff --- /dev/null +++ b/runtime/syscall.h @@ -0,0 +1,160 @@ +/* syscall defines and inlines + * 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. + */ + +#ifndef _SYSCALL_H_ /* -*- linux-c -*- */ +#define _SYSCALL_H_ + +#if defined(__i386__) || defined(CONFIG_IA32_EMULATION) +#define __MMAP_SYSCALL_NO_IA32 192 /* mmap2 */ +#define __MPROTECT_SYSCALL_NO_IA32 125 +#define __MUNMAP_SYSCALL_NO_IA32 91 +#define __MREMAP_SYSCALL_NO_IA32 163 +# if !defined(CONFIG_IA32_EMULATION) +#define MMAP_SYSCALL_NO(tsk) __MMAP_SYSCALL_NO_IA32 +#define MPROTECT_SYSCALL_NO(tsk) __MPROTECT_SYSCALL_NO_IA32 +#define MUNMAP_SYSCALL_NO(tsk) __MUNMAP_SYSCALL_NO_IA32 +#define MREMAP_SYSCALL_NO(tsk) __MREMAP_SYSCALL_NO_IA32 +# endif +#endif + +#if defined(__x86_64__) +#define __MMAP_SYSCALL_NO_X86_64 9 +#define __MPROTECT_SYSCALL_NO_X86_64 10 +#define __MUNMAP_SYSCALL_NO_X86_64 11 +#define __MREMAP_SYSCALL_NO_X86_64 25 +# if defined(CONFIG_IA32_EMULATION) +#define MMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \ + ? __MMAP_SYSCALL_NO_IA32 \ + : __MMAP_SYSCALL_NO_X86_64) +#define MPROTECT_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \ + ? __MPROTECT_SYSCALL_NO_IA32 \ + : __MPROTECT_SYSCALL_NO_X86_64) +#define MUNMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \ + ? __MUNMAP_SYSCALL_NO_IA32 \ + : __MUNMAP_SYSCALL_NO_X86_64) +#define MREMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_IA32)) \ + ? __MREMAP_SYSCALL_NO_IA32 \ + : __MREMAP_SYSCALL_NO_X86_64) +# else +#define MMAP_SYSCALL_NO(tsk) __MMAP_SYSCALL_NO_X86_64 +#define MPROTECT_SYSCALL_NO(tsk) __MPROTECT_SYSCALL_NO_X86_64 +#define MUNMAP_SYSCALL_NO(tsk) __MUNMAP_SYSCALL_NO_X86_64 +#define MREMAP_SYSCALL_NO(tsk) __MREMAP_SYSCALL_NO_X86_64 +# endif +#endif + +#if !defined(MMAP_SYSCALL_NO) || !defined(MPROTECT_SYSCALL_NO) \ + || !defined(MUNMAP_SYSCALL_NO) || !defined(MREMAP_SYSCALL_NO) +#error "Unimplemented architecture" +#endif + +#if defined(__i386__) || defined(__x86_64__) +static inline unsigned long +__stp_user_syscall_nr(struct pt_regs *regs) +{ +#if defined(STAPCONF_X86_UNIREGS) + return regs->orig_ax; +#elif defined(__x86_64__) + return regs->orig_rax; +#elif defined (__i386__) + return regs->orig_eax; +#endif +} +#endif + +#if defined(__i386__) || defined(__x86_64__) +static inline long * +__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +{ +#ifdef CONFIG_IA32_EMULATION +// This code works, but isn't what we need. Since +// __stp_user_syscall_arg() doesn't sign-extend, a value passed in as +// an argument and then returned won't compare correctly anymore. So, +// for now, disable this code. +# if 0 + if (test_tsk_thread_flag(task, TIF_IA32)) + // Sign-extend the value so (int)-EFOO becomes (long)-EFOO + // and will match correctly in comparisons. + regs->ax = (long) (int) regs->ax; +# endif +#endif +#if defined(STAPCONF_X86_UNIREGS) + return ®s->ax; +#elif defined(__x86_64__) + return ®s->rax; +#elif defined (__i386__) + return ®s->eax; +#endif +} +#endif + +#if defined(__i386__) || defined(__x86_64__) +static inline long * +__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, + unsigned int n) +{ +#if defined(__i386__) + if (n > 5) { + _stp_error("syscall arg > 5"); + return NULL; + } +#if defined(STAPCONF_X86_UNIREGS) + return ®s->bx + n; +#else + return ®s->ebx + n; +#endif +#elif defined(__x86_64__) +#ifdef CONFIG_IA32_EMULATION + if (test_tsk_thread_flag(task, TIF_IA32)) + switch (n) { +#if defined(STAPCONF_X86_UNIREGS) + case 0: return ®s->bx; + case 1: return ®s->cx; + case 2: return ®s->dx; + case 3: return ®s->si; + case 4: return ®s->di; + case 5: return ®s->bp; +#else + case 0: return ®s->rbx; + case 1: return ®s->rcx; + case 2: return ®s->rdx; + case 3: return ®s->rsi; + case 4: return ®s->rdi; + case 5: return ®s->rbp; +#endif + default: + _stp_error("syscall arg > 5"); + return NULL; + } +#endif /* CONFIG_IA32_EMULATION */ + switch (n) { +#if defined(STAPCONF_X86_UNIREGS) + case 0: return ®s->di; + case 1: return ®s->si; + case 2: return ®s->dx; + case 3: return ®s->r10; + case 4: return ®s->r8; + case 5: return ®s->r9; +#else + case 0: return ®s->rdi; + case 1: return ®s->rsi; + case 2: return ®s->rdx; + case 3: return ®s->r10; + case 4: return ®s->r8; + case 5: return ®s->r9; +#endif + default: + _stp_error("syscall arg > 5"); + return NULL; + } +#endif /* CONFIG_X86_32 */ +} +#endif + +#endif /* _SYSCALL_H_ */ diff --git a/runtime/task_finder.c b/runtime/task_finder.c index e78caab6..71b11569 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -1,5 +1,7 @@ #include <linux/list.h> #include <linux/binfmts.h> +#include "syscall.h" +#include "task_finder_vma.c" static LIST_HEAD(__stp_task_finder_list); @@ -11,10 +13,44 @@ struct stap_task_finder_target; #define __STP_TF_STOPPED 3 atomic_t __stp_task_finder_state = ATOMIC_INIT(__STP_TF_STARTING); +#ifdef DEBUG_TASK_FINDER +atomic_t __stp_attach_count = ATOMIC_INIT (0); + +#define debug_task_finder_attach() (atomic_inc(&__stp_attach_count)) +#define debug_task_finder_detach() (atomic_dec(&__stp_attach_count)) +#define debug_task_finder_report() (_stp_dbug(__FUNCTION__, __LINE__, \ + "attach count: %d\n", atomic_read(&__stp_attach_count))) +#else +#define debug_task_finder_attach() /* empty */ +#define debug_task_finder_detach() /* empty */ +#define debug_task_finder_report() /* empty */ +#endif + typedef int (*stap_task_finder_callback)(struct task_struct *tsk, int register_p, + int process_p, struct stap_task_finder_target *tgt); +typedef int (*stap_task_finder_vm_callback)(struct task_struct *tsk, + int map_p, char *vm_path, + unsigned long vm_start, + unsigned long vm_end, + unsigned long vm_pgoff); + +#ifdef DEBUG_TASK_FINDER_VMA +int __stp_tf_vm_cb(struct task_struct *tsk, + int map_p, char *vm_path, + unsigned long vm_start, + unsigned long vm_end, + unsigned long vm_pgoff) +{ + _stp_dbug(__FUNCTION__, __LINE__, + "vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n", + tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff); + return 0; +} +#endif + struct stap_task_finder_target { /* private: */ struct list_head list; /* __stp_task_finder_list linkage */ @@ -28,12 +64,27 @@ struct stap_task_finder_target { const char *pathname; pid_t pid; stap_task_finder_callback callback; + stap_task_finder_vm_callback vm_callback; }; static u32 __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct task_struct *tsk); +static u32 +__stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, + struct task_struct *tsk); + +static u32 +__stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs); + +static u32 +__stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs); + static int stap_register_task_finder_target(struct stap_task_finder_target *new_tgt) { @@ -56,6 +107,11 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt) new_tgt->engine_attached = 0; memset(&new_tgt->ops, 0, sizeof(new_tgt->ops)); new_tgt->ops.report_death = &__stp_utrace_task_finder_target_death; + new_tgt->ops.report_quiesce = &__stp_utrace_task_finder_target_quiesce; + new_tgt->ops.report_syscall_entry = \ + &__stp_utrace_task_finder_target_syscall_entry; + new_tgt->ops.report_syscall_exit = \ + &__stp_utrace_task_finder_target_syscall_exit; // Search the list for an existing entry for pathname/pid. list_for_each(node, &__stp_task_finder_list) { @@ -115,6 +171,7 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops) } else if (engine != NULL) { utrace_detach(tsk, engine); + debug_task_finder_detach(); } } } while_each_thread(grp, tsk); @@ -125,6 +182,7 @@ udo_err: _stp_error("utrace_attach returned error %d on pid %d", error, pid); } + debug_task_finder_report(); } static void @@ -190,16 +248,28 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen) return rc; } -#define __STP_UTRACE_TASK_FINDER_EVENTS (UTRACE_EVENT(CLONE) \ - | UTRACE_EVENT(EXEC) \ - | UTRACE_EVENT(DEATH)) +#define __STP_TASK_FINDER_EVENTS (UTRACE_EVENT(CLONE) \ + | UTRACE_EVENT(EXEC) \ + | UTRACE_EVENT(DEATH)) + +#define __STP_ATTACHED_TASK_BASE_EVENTS (UTRACE_EVENT(DEATH)) + +#define __STP_ATTACHED_TASK_VM_BASE_EVENTS (__STP_ATTACHED_TASK_BASE_EVENTS \ + | UTRACE_EVENT(SYSCALL_ENTRY) \ + | UTRACE_EVENT(SYSCALL_EXIT)) + +#define __STP_ATTACHED_TASK_VM_EVENTS (__STP_ATTACHED_TASK_VM_BASE_EVENTS \ + | UTRACE_ACTION_QUIESCE \ + | UTRACE_EVENT(QUIESCE)) -#define __STP_UTRACE_ATTACHED_TASK_EVENTS (UTRACE_EVENT(DEATH)) +#define __STP_ATTACHED_TASK_EVENTS(tgt) \ + ((((tgt)->vm_callback) == NULL) ? __STP_ATTACHED_TASK_BASE_EVENTS \ + : __STP_ATTACHED_TASK_VM_EVENTS) static int -__stp_utrace_attach(struct task_struct *tsk, - const struct utrace_engine_ops *ops, void *data, - unsigned long event_flags) +stap_utrace_attach(struct task_struct *tsk, + const struct utrace_engine_ops *ops, void *data, + unsigned long event_flags) { struct utrace_attached_engine *engine; struct mm_struct *mm; @@ -231,13 +301,15 @@ __stp_utrace_attach(struct task_struct *tsk, } else { utrace_set_flags(tsk, engine, event_flags); + debug_task_finder_attach(); } return rc; } static inline void __stp_utrace_attach_match_filename(struct task_struct *tsk, - const char * const filename) + const char * const filename, + int register_p, int process_p) { size_t filelen; struct list_head *tgt_node; @@ -270,72 +342,114 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk, continue; if (cb_tgt->callback != NULL) { - int rc = cb_tgt->callback(tsk, 1, cb_tgt); + int rc = cb_tgt->callback(tsk, register_p, + process_p, cb_tgt); if (rc != 0) { - _stp_error("exec callback for %d failed: %d", + _stp_error("callback for %d failed: %d", (int)tsk->pid, rc); break; } } - // Set up thread death notification. - rc = __stp_utrace_attach(tsk, &cb_tgt->ops, cb_tgt, - __STP_UTRACE_ATTACHED_TASK_EVENTS); - if (rc != 0 && rc != EPERM) - break; - cb_tgt->engine_attached = 1; + // Set up events we need for attached tasks. + if (register_p) { + rc = stap_utrace_attach(tsk, &cb_tgt->ops, + cb_tgt, + __STP_ATTACHED_TASK_EVENTS(cb_tgt)); + if (rc != 0 && rc != EPERM) + break; + cb_tgt->engine_attached = 1; + } + else { + struct utrace_attached_engine *engine; + engine = utrace_attach(tsk, + UTRACE_ATTACH_MATCH_OPS, + &cb_tgt->ops, 0); + if (! IS_ERR(engine) && engine != NULL) { + utrace_detach(tsk, engine); + debug_task_finder_detach(); + } + } } } } -static u32 -__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine, - struct task_struct *parent, - unsigned long clone_flags, - struct task_struct *child) +// This function handles the details of getting a task's associated +// pathname, and calling __stp_utrace_attach_match_filename() to +// attach to it if we find the pathname "interesting". So, what's the +// difference between path_tsk and match_tsk? Normally they are the +// same, except in one case. In an UTRACE_EVENT(EXEC), we need to +// detach engines from the newly exec'ed process (since its path has +// changed). In this case, we have to match the path of the parent +// (path_tsk) against the child (match_tsk). + +static void +__stp_utrace_attach_match_tsk(struct task_struct *path_tsk, + struct task_struct *match_tsk, int register_p, + int process_p) { - int rc; struct mm_struct *mm; char *mmpath_buf; char *mmpath; - if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) - return UTRACE_ACTION_RESUME; - - // On clone, attach to the child. - rc = __stp_utrace_attach(child, engine->ops, 0, - __STP_UTRACE_TASK_FINDER_EVENTS); - if (rc != 0 && rc != EPERM) - return UTRACE_ACTION_RESUME; + if (path_tsk->pid <= 1 || match_tsk->pid <= 1) + return; - /* Grab the path associated with this task. */ - mm = get_task_mm(child); + /* Grab the path associated with the path_tsk. */ + mm = get_task_mm(path_tsk); if (! mm) { /* If the thread doesn't have a mm_struct, it is * a kernel thread which we need to skip. */ - return UTRACE_ACTION_RESUME; + return; } // Allocate space for a path mmpath_buf = _stp_kmalloc(PATH_MAX); if (mmpath_buf == NULL) { + mmput(mm); _stp_error("Unable to allocate space for path"); - return UTRACE_ACTION_RESUME; + return; } // Grab the path associated with the new task mmpath = __stp_get_mm_path(mm, mmpath_buf, PATH_MAX); mmput(mm); /* We're done with mm */ if (mmpath == NULL || IS_ERR(mmpath)) { - rc = -PTR_ERR(mmpath); + int rc = -PTR_ERR(mmpath); _stp_error("Unable to get path (error %d) for pid %d", - rc, (int)child->pid); + rc, (int)path_tsk->pid); } else { - __stp_utrace_attach_match_filename(child, mmpath); + __stp_utrace_attach_match_filename(match_tsk, mmpath, + register_p, process_p); } _stp_kfree(mmpath_buf); + return; +} + +static u32 +__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine, + struct task_struct *parent, + unsigned long clone_flags, + struct task_struct *child) +{ + int rc; + struct mm_struct *mm; + char *mmpath_buf; + char *mmpath; + + if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) + return UTRACE_ACTION_RESUME; + + // On clone, attach to the child. + rc = stap_utrace_attach(child, engine->ops, 0, + __STP_TASK_FINDER_EVENTS); + if (rc != 0 && rc != EPERM) + return UTRACE_ACTION_RESUME; + + __stp_utrace_attach_match_tsk(parent, child, 1, + (clone_flags & CLONE_THREAD) == 0); return UTRACE_ACTION_RESUME; } @@ -353,11 +467,25 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine, if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) return UTRACE_ACTION_RESUME; - // On exec, check bprm - if (bprm->filename == NULL) - return UTRACE_ACTION_RESUME; + // When exec'ing, we need to let callers detach from the + // parent thread (if necessary). For instance, assume + // '/bin/bash' clones and then execs '/bin/ls'. If the user + // was probing '/bin/bash', the cloned thread is still + // '/bin/bash' up until the exec. +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) +#define real_parent parent +#endif + if (tsk != NULL && tsk->real_parent != NULL + && tsk->real_parent->pid > 1) { + // We'll hardcode this as a process end, but a thread + // *could* call exec (although they aren't supposed to). + __stp_utrace_attach_match_tsk(tsk->real_parent, tsk, 0, 1); + } - __stp_utrace_attach_match_filename(tsk, bprm->filename); + // We assume that all exec's are exec'ing a new process. Note + // that we don't use bprm->filename, since that path can be + // relative. + __stp_utrace_attach_match_tsk(tsk, tsk, 1, 1); return UTRACE_ACTION_RESUME; } @@ -366,6 +494,7 @@ static u32 stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine, struct task_struct *tsk) { + debug_task_finder_detach(); return UTRACE_ACTION_DETACH; } @@ -376,6 +505,7 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, struct stap_task_finder_target *tgt = engine->data; if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { + debug_task_finder_detach(); return UTRACE_ACTION_DETACH; } @@ -392,15 +522,368 @@ __stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine, int rc; // Call the callback - rc = tgt->callback(tsk, 0, tgt); + rc = tgt->callback(tsk, 0, + (atomic_read(&tsk->signal->live) == 0), + tgt); if (rc != 0) { _stp_error("death callback for %d failed: %d", (int)tsk->pid, rc); } } + debug_task_finder_detach(); return UTRACE_ACTION_DETACH; } +static u32 +__stp_utrace_task_finder_target_quiesce(struct utrace_attached_engine *engine, + struct task_struct *tsk) +{ + struct stap_task_finder_target *tgt = engine->data; + + // Turn off quiesce handling. + utrace_set_flags(tsk, engine, __STP_ATTACHED_TASK_VM_BASE_EVENTS); + + if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { + debug_task_finder_detach(); + return UTRACE_ACTION_DETACH; + } + + if (tgt != NULL && tgt->vm_callback != NULL) { + struct mm_struct *mm; + char *mmpath_buf; + char *mmpath; + struct vm_area_struct *vma; + int rc; + + /* Call the vm_callback for every vma associated with + * a file. */ + mm = get_task_mm(tsk); + if (! mm) + goto utftq_out; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + mmput(mm); + _stp_error("Unable to allocate space for path"); + goto utftq_out; + } + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + if (vma->vm_file) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + mmpath = d_path(vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt, + mmpath_buf, PATH_MAX); +#else + mmpath = d_path(&(vma->vm_file->f_path), + mmpath_buf, PATH_MAX); +#endif + if (mmpath) { + // Call the callback + rc = tgt->vm_callback(tsk, 1, mmpath, + vma->vm_start, + vma->vm_end, + vma->vm_pgoff); + if (rc != 0) { + _stp_error("vm callback for %d failed: %d", + (int)tsk->pid, rc); + } + + } + else { + _stp_dbug(__FUNCTION__, __LINE__, + "no mmpath?\n"); + } + } + vma = vma->vm_next; + } + up_read(&mm->mmap_sem); + mmput(mm); /* We're done with mm */ + _stp_kfree(mmpath_buf); + } + +utftq_out: + return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_RESUME); +} + + +struct vm_area_struct * +__stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) +{ + struct vm_area_struct *vma = find_vma(mm, addr); + + // I'm not positive why the checking for vm_start > addr is + // necessary, but it seems to be (sometimes find_vma() returns + // a vma that addr doesn't belong to). + if (vma && (vma->vm_file == NULL || vma->vm_start > addr)) + vma = NULL; + return vma; +} + +static u32 +__stp_utrace_task_finder_target_syscall_entry(struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs) +{ + struct stap_task_finder_target *tgt = engine->data; + unsigned long syscall_no; + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long *arg0_addr, arg0; + int rc; + + if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { + debug_task_finder_detach(); + return UTRACE_ACTION_DETACH; + } + + if (tgt == NULL || tgt->vm_callback == NULL) + return UTRACE_ACTION_RESUME; + + // See if syscall is one we're interested in. + // + // FIXME: do we need to handle mremap()? + syscall_no = __stp_user_syscall_nr(regs); + if (syscall_no != MMAP_SYSCALL_NO(tsk) + && syscall_no != MPROTECT_SYSCALL_NO(tsk) + && syscall_no != MUNMAP_SYSCALL_NO(tsk)) + return UTRACE_ACTION_RESUME; + + + // We need the first syscall argument to see what address + // we're operating on. + arg0_addr = __stp_user_syscall_arg(tsk, regs, 0); + if ((rc = __stp_get_user(arg0, arg0_addr)) != 0) { + _stp_error("couldn't read syscall arg 0 for pid %d: %d", + tsk->pid, rc); + } + else if (arg0 != (unsigned long)NULL) { + mm = get_task_mm(tsk); + if (mm) { + down_read(&mm->mmap_sem); + + // If we can find a matching vma associated + // with a file, save off its details. + vma = __stp_find_file_based_vma(mm, arg0); + if (vma != NULL) { + __stp_tf_add_vma(tsk, arg0, vma); + } + + up_read(&mm->mmap_sem); + mmput(mm); + } + } + return UTRACE_ACTION_RESUME; +} + +static void +__stp_target_call_vm_callback(struct stap_task_finder_target *tgt, + struct task_struct *tsk, + struct vm_area_struct *vma) +{ + char *mmpath_buf; + char *mmpath; + int rc; + + // Allocate space for a path + mmpath_buf = _stp_kmalloc(PATH_MAX); + if (mmpath_buf == NULL) { + _stp_error("Unable to allocate space for path"); + return; + } + + // Grab the path associated with this vma. +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + mmpath = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt, + mmpath_buf, PATH_MAX); +#else + mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, PATH_MAX); +#endif + if (mmpath == NULL || IS_ERR(mmpath)) { + rc = -PTR_ERR(mmpath); + _stp_error("Unable to get path (error %d) for pid %d", + rc, (int)tsk->pid); + } + else { + rc = tgt->vm_callback(tsk, 1, mmpath, vma->vm_start, + vma->vm_end, vma->vm_pgoff); + if (rc != 0) { + _stp_error("vm callback for %d failed: %d", + (int)tsk->pid, rc); + } + } + _stp_kfree(mmpath_buf); +} + +static u32 +__stp_utrace_task_finder_target_syscall_exit(struct utrace_attached_engine *engine, + struct task_struct *tsk, + struct pt_regs *regs) +{ + struct stap_task_finder_target *tgt = engine->data; + unsigned long syscall_no; + unsigned long *rv_addr, rv; + unsigned long *arg0_addr, arg0; + int rc; + struct mm_struct *mm; + struct vm_area_struct *vma; + struct __stp_tf_vma_entry *entry = NULL; + + if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { + debug_task_finder_detach(); + return UTRACE_ACTION_DETACH; + } + + if (tgt == NULL || tgt->vm_callback == NULL) + return UTRACE_ACTION_RESUME; + + // See if syscall is one we're interested in. + // + // FIXME: do we need to handle mremap()? + syscall_no = __stp_user_syscall_nr(regs); + if (syscall_no != MMAP_SYSCALL_NO(tsk) + && syscall_no != MPROTECT_SYSCALL_NO(tsk) + && syscall_no != MUNMAP_SYSCALL_NO(tsk)) + return UTRACE_ACTION_RESUME; + + // Get return value + rv_addr = __stp_user_syscall_return_value(tsk, regs); + if ((rc = __stp_get_user(rv, rv_addr)) != 0) { + _stp_error("couldn't read syscall return value for pid %d: %d", + tsk->pid, rc); + return UTRACE_ACTION_RESUME; + } + + // We need the first syscall argument to see what address we + // were operating on. + arg0_addr = __stp_user_syscall_arg(tsk, regs, 0); + if ((rc = __stp_get_user(arg0, arg0_addr)) != 0) { + _stp_error("couldn't read syscall arg 0 for pid %d: %d", + tsk->pid, rc); + return UTRACE_ACTION_RESUME; + } + +#ifdef DEBUG_TASK_FINDER_VMA + _stp_dbug(__FUNCTION__, __LINE__, + "tsk %d found %s(0x%lx), returned 0x%lx\n", + tsk->pid, + ((syscall_no == MMAP_SYSCALL_NO(tsk)) ? "mmap" + : ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect" + : ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap" + : "UNKNOWN"))), + arg0, rv); +#endif + + // Try to find the vma info we might have saved. + if (arg0 != (unsigned long)NULL) + entry = __stp_tf_get_vma_entry(tsk, arg0); + + // If entry is NULL, this means we didn't find a file based + // vma to store in the syscall_entry routine. This could mean + // we just created a new vma. + if (entry == NULL) { + mm = get_task_mm(tsk); + if (mm) { + down_read(&mm->mmap_sem); + vma = __stp_find_file_based_vma(mm, rv); + if (vma != NULL) { + __stp_target_call_vm_callback(tgt, tsk, + vma); + } + up_read(&mm->mmap_sem); + mmput(mm); + } + } + // If we found saved vma information, try to match it up with + // what currently exists. + else { +#ifdef DEBUG_TASK_FINDER_VMA + _stp_dbug(__FUNCTION__, __LINE__, + "** found stored vma 0x%lx/0x%lx/0x%lx!\n", + entry->vm_start, entry->vm_end, entry->vm_pgoff); +#endif + mm = get_task_mm(tsk); + if (mm) { + down_read(&mm->mmap_sem); + vma = __stp_find_file_based_vma(mm, entry->vm_start); + + // We couldn't find the vma at all. The + // original vma was deleted. + if (vma == NULL) { + // FIXME: We'll need to figure out to + // retrieve the path of a deleted + // vma. + rc = tgt->vm_callback(tsk, 0, NULL, + entry->vm_start, + entry->vm_end, + entry->vm_pgoff); + if (rc != 0) { + _stp_error("vm callback for %d failed: %d", + (int)tsk->pid, rc); + } + } + + // If nothing has changed, there is no + // need to call the callback. + else if (vma->vm_start == entry->vm_start + && vma->vm_end == entry->vm_end + && vma->vm_pgoff == entry->vm_pgoff) { + // do nothing + } + + // The original vma has been changed. It is + // possible that calling mprotect (e.g.) split + // up an existing vma into 2 or 3 new vma's + // (assuming it protected a portion of the + // original vma at the beginning, middle, or + // end). Try to determine what happened. + else { + unsigned long tmp; + + // First report that the original vma + // is gone. + // + // FIXME: We'll need to figure out to + // retrieve the path of a deleted + // vma. + rc = tgt->vm_callback(tsk, 0, NULL, + entry->vm_start, + entry->vm_end, + entry->vm_pgoff); + if (rc != 0) { + _stp_error("vm callback for %d failed: %d", + (int)tsk->pid, rc); + } + + // Now find all the new vma's that + // made up the original vma's address + // space and call the callback on each + // new vma. + tmp = entry->vm_start; + while (((vma = __stp_find_file_based_vma(mm, + tmp)) + != NULL) + && vma->vm_end <= entry->vm_end) { + __stp_target_call_vm_callback(tgt, tsk, + vma); + if (vma->vm_end >= entry->vm_end) + break; + tmp = vma->vm_end; + } + } + up_read(&mm->mmap_sem); + mmput(mm); + } + + // Cleanup by deleting the saved vma info. + __stp_tf_remove_vma_entry(entry); + } + return UTRACE_ACTION_RESUME; +} + struct utrace_engine_ops __stp_utrace_task_finder_ops = { .report_clone = __stp_utrace_task_finder_report_clone, .report_exec = __stp_utrace_task_finder_report_exec, @@ -429,8 +912,8 @@ stap_start_task_finder(void) size_t mmpathlen; struct list_head *tgt_node; - rc = __stp_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0, - __STP_UTRACE_TASK_FINDER_EVENTS); + rc = stap_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0, + __STP_TASK_FINDER_EVENTS); if (rc == EPERM) { /* Ignore EPERM errors, which mean this wasn't * a thread we can attach to. */ @@ -482,21 +965,27 @@ stap_start_task_finder(void) cb_tgt = list_entry(cb_node, struct stap_task_finder_target, callback_list); - if (cb_tgt == NULL || cb_tgt->callback == NULL) + if (cb_tgt == NULL) continue; - // Call the callback. - rc = cb_tgt->callback(tsk, 1, cb_tgt); - if (rc != 0) { - _stp_error("attach callback for %d failed: %d", - (int)tsk->pid, rc); - goto stf_err; + // Call the callback. Assume that if + // the thread is a thread group + // leader, it is a process. + if (cb_tgt->callback != NULL) { + rc = cb_tgt->callback(tsk, 1, + (tsk->pid == tsk->tgid), + cb_tgt); + if (rc != 0) { + _stp_error("attach callback for %d failed: %d", + (int)tsk->pid, rc); + goto stf_err; + } } - // Set up thread death notification. - rc = __stp_utrace_attach(tsk, &cb_tgt->ops, - cb_tgt, - __STP_UTRACE_ATTACHED_TASK_EVENTS); + // Set up events we need for attached tasks. + rc = stap_utrace_attach(tsk, &cb_tgt->ops, + cb_tgt, + __STP_ATTACHED_TASK_EVENTS(cb_tgt)); if (rc != 0 && rc != EPERM) goto stf_err; cb_tgt->engine_attached = 1; @@ -514,7 +1003,9 @@ static void stap_stop_task_finder(void) { atomic_set(&__stp_task_finder_state, __STP_TF_STOPPING); + debug_task_finder_report(); stap_utrace_detach_ops(&__stp_utrace_task_finder_ops); __stp_task_finder_cleanup(); + debug_task_finder_report(); atomic_set(&__stp_task_finder_state, __STP_TF_STOPPED); } diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c new file mode 100644 index 00000000..76b5c059 --- /dev/null +++ b/runtime/task_finder_vma.c @@ -0,0 +1,112 @@ +#include <linux/list.h> +#include <linux/jhash.h> +#include <linux/mutex.h> + +// __stp_tf_vma_mutex protects the hash table. +static DEFINE_MUTEX(__stp_tf_vma_mutex); + +#define __STP_TF_HASH_BITS 4 +#define __STP_TF_TABLE_SIZE (1 << __STP_TF_HASH_BITS) + +struct __stp_tf_vma_entry { + struct hlist_node hlist; + + pid_t pid; + unsigned long addr; + unsigned long vm_start; + unsigned long vm_end; + unsigned long vm_pgoff; + // Is that enough? Should we store a dcookie for vm_file? +}; + +static struct hlist_head __stp_tf_vma_table[__STP_TF_TABLE_SIZE]; + +static inline u32 +__stp_tf_vma_hash(struct task_struct *tsk, unsigned long addr) +{ +#ifdef CONFIG_64BIT + return (jhash_3words(tsk->pid, (u32)addr, (u32)(addr >> 32), 0) + & (__STP_TF_TABLE_SIZE - 1)); +#else + return (jhash_2words(tsk->pid, addr, 0) & (__STP_TF_TABLE_SIZE - 1)); +#endif +} + + +// Get vma_entry if the vma is present in the vma hash table. +// Returns NULL if not present. +static struct __stp_tf_vma_entry * +__stp_tf_get_vma_entry(struct task_struct *tsk, unsigned long addr) +{ + struct hlist_head *head; + struct hlist_node *node; + struct __stp_tf_vma_entry *entry; + + mutex_lock(&__stp_tf_vma_mutex); + head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)]; + hlist_for_each_entry(entry, node, head, hlist) { + if (tsk->pid == entry->pid + && addr == entry->addr) { + mutex_unlock(&__stp_tf_vma_mutex); + return entry; + } + } + mutex_unlock(&__stp_tf_vma_mutex); + return NULL; +} + +// Add the vma info to the vma hash table. +static int +__stp_tf_add_vma(struct task_struct *tsk, unsigned long addr, + struct vm_area_struct *vma) +{ + struct hlist_head *head; + struct hlist_node *node; + struct __stp_tf_vma_entry *entry; + + mutex_lock(&__stp_tf_vma_mutex); + head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)]; + hlist_for_each_entry(entry, node, head, hlist) { + if (tsk->pid == entry->pid + && addr == entry->addr) { + printk(KERN_NOTICE + "vma (pid: %d, vm_start: 0x%lx) present?\n", + tsk->pid, vma->vm_start); + mutex_unlock(&__stp_tf_vma_mutex); + return -EBUSY; /* Already there */ + } + } + + // Using kmalloc here to allocate an element. Could cause some + // memory fragmentation if overused. + entry = kmalloc(sizeof(struct __stp_tf_vma_entry), GFP_KERNEL); + if (!entry) { + mutex_unlock(&__stp_tf_vma_mutex); + return -ENOMEM; + } + entry->pid = tsk->pid; + entry->addr = addr; + entry->vm_start = vma->vm_start; + entry->vm_end = vma->vm_end; + entry->vm_pgoff = vma->vm_pgoff; + hlist_add_head(&entry->hlist, head); + mutex_unlock(&__stp_tf_vma_mutex); + return 0; +} + +// Remove the vma entry from the vma hash table. +static int +__stp_tf_remove_vma_entry(struct __stp_tf_vma_entry *entry) +{ + struct hlist_head *head; + struct hlist_node *node; + int found = 0; + + if (entry != NULL) { + mutex_lock(&__stp_tf_vma_mutex); + hlist_del(&entry->hlist); + kfree(entry); + mutex_unlock(&__stp_tf_vma_mutex); + } + return 0; +} diff --git a/runtime/tests/ChangeLog b/runtime/tests/ChangeLog deleted file mode 100644 index 38634d0f..00000000 --- a/runtime/tests/ChangeLog +++ /dev/null @@ -1,112 +0,0 @@ -2006-01-25 Martin Hunt <hunt@redhat.com> - - * agg/stats.c (main): Delete Stats when done. - -2005-12-08 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Add size test. - * pmaps/pmap.test: Add size test. - -2005-12-07 Martin Hunt <hunt@redhat.com> - - * agg/agg.test: Adjust results to match - the more compact histogram format. - - * pmaps/*.c: Change pmap type from MAP to PMAP. - - * pmaps/pmap.test: Adjust results to match - the more compact histogram format. - - * maps/map.test: Adjust results to match - the more compact histogram format. - -2005-11-28 Martin Hunt <hunt@redhat.com> - - * pmaps/pmap.test: Add ix_log and ix_none. - * pmaps/ix_log.c: Test log histograms. - * pmaps/ix_none.c: Test no histograms. - -2005-11-10 Martin Hunt <hunt@redhat.com> - * pmaps/ix2.c: New test. Test _stp_pmap_get_*(). - * pmaps/iii3.c: New test. Test _stp_pmap_get_*(). - * pmaps/pmap.test: Update. - -2005-11-10 Martin Hunt <hunt@redhat.com> - * pmaps/ii2.c: New test of maps and pmaps with the same keysym. - * pmaps/pmap.test: Update. - -2005-11-09 Martin Hunt <hunt@redhat.com> - - * maps/sort2.c: New file. - * maps/sort_stat.c: New file. - * maps/map.test: Update - -2005-11-08 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Remove old map API tests. - * maps/ii2.c: Renamed ii.c. - * maps/iiss2.c: Renamed iiss.c. - * maps/is2.c: Renamed is.c. - * maps/issii2.c: Renamed issii.c. - * maps/isx2.c: Renamed isx.c. - * maps/map_format2.c: Renamed map_format.c. - * maps/si2.c: Renamed si.c. - * maps/keys.c: Deleted - * maps/test_list_int64.c: Deleted. - * maps/test_list_string.c: Deleted. - * maps/sort.c: Update to use new map API. - -2005-11-08 Martin Hunt <hunt@redhat.com> - - * pmaps/*: Add new pmaps tests. - -2005-10-28 Martin Hunt <hunt@redhat.com> - * maps/keys.c: New file. Tests specific to _stp_key_get_*(). - - * maps/iiss2.c (main): Add some comments to make clear expected - results. - * maps/is2.c (main): _stp_map_get_*s() now returns "" instead - of NULL when lookup fails. _stp_map_set_*s() now deletes a node - when setting to "" (as well as NULL). - * maps/setadd.c (main): Ditto. - * maps/map.test: update results. - -2005-10-26 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Add results for iiiiii and ssssss. - * maps/iiiiii.c: New file. - * maps/ssssss.c: New file. - -2005-10-26 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Add results for issii2. - -2005-10-26 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Update with results for new tests. - * maps/*2.c: Tests for the new API. - * maps/ist.c: Renamed isx.c. - * maps/setadd.c: New test of adding and setting. - -2005-09-23 Martin Hunt <hunt@redhat.com> - - * maps/map.test: Add sort results. - * maps/sort.c: New test. - -2005-09-14 Martin Hunt <hunt@redhat.com> - - * maps/ii.c (main): Add test for _stp_map_clear(). - * maps/map.test: Update results. - -2005-09-12 Martin Hunt <hunt@redhat.com> - - * math/div64.c (main): Set the expected result for LLONG_MIN/-1 to - be LLONG_MIN (overflow) instead of 0. - -2005-09-09 Martin Hunt <hunt@redhat.com> - - * math/div64.c (main): Fixes for running on 64-bit hardware. - - * README: Update. - * math/div64.c: New file. 64-bit division tests. - diff --git a/runtime/tests/Makefile b/runtime/tests/Makefile deleted file mode 100644 index 4e744d25..00000000 --- a/runtime/tests/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -tests: - tclsh all.tcl - diff --git a/runtime/tests/README b/runtime/tests/README deleted file mode 100644 index 000f1017..00000000 --- a/runtime/tests/README +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains the user-levels tests. - -Before running these for the first time, -> cd ../user -> ./recreate_links - -To run the test here, just type "make". diff --git a/runtime/tests/agg/Makefile b/runtime/tests/agg/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/agg/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/agg/agg.test b/runtime/tests/agg/agg.test deleted file mode 100644 index 2d56f031..00000000 --- a/runtime/tests/agg/agg.test +++ /dev/null @@ -1,169 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -cd $tcltest::testsDirectory - -set CFLAGS "-Os" -set KPATH "/lib/modules/[exec uname -r]/build/include" -set MPATH "/lib/modules/[exec uname -r]/build/include/asm/mach-default" -set PATH "../../user" - -test Counter {Counter Test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test count.c -} -body { - exec ./test -} -result {cnt1[0] = 1 -cnt2[0] = 10 -cnt1[1] = 2 -cnt2[1] = 11 -cnt1[2] = 3 -cnt2[2] = 12 -cnt1[3] = 4 -cnt2[3] = 13 -cnt1[4] = 5 -cnt2[4] = 14 -cnt1[5] = 6 -cnt2[5] = 15 -cnt1[6] = 7 -cnt2[6] = 16 -cnt1[7] = 8 -cnt2[7] = 17 -cnt1 = 36 -cnt2 = 108 --------------------- -cnt1[0] = 2 -cnt2[0] = 20 -cnt1[1] = 4 -cnt2[1] = 22 -cnt1[2] = 6 -cnt2[2] = 24 -cnt1[3] = 8 -cnt2[3] = 26 -cnt1[4] = 10 -cnt2[4] = 28 -cnt1[5] = 12 -cnt2[5] = 30 -cnt1[6] = 14 -cnt2[6] = 32 -cnt1[7] = 16 -cnt2[7] = 34 -cnt1 = 72 -cnt2 = 216 --------------------- -cnt1 = 140 -cnt2 = 784 -cnt1 = 0 -cnt2 = 0 --------------------- -cnt1[0] = 0 -cnt2[0] = 0 -cnt1[1] = 1 -cnt2[1] = 1 -cnt1[2] = 4 -cnt2[2] = 8 -cnt1[3] = 9 -cnt2[3] = 27 -cnt1[4] = 16 -cnt2[4] = 64 -cnt1[5] = 25 -cnt2[5] = 125 -cnt1[6] = 36 -cnt2[6] = 216 -cnt1[7] = 49 -cnt2[7] = 343 -cnt1 = 140 -cnt2 = 784} - -test Stats {Stats Test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test stats.c -} -body { - exec ./test -} -result {st1[0] = count: 1 sum:1 -st2[0] = count: 1 sum:10 -st3[0] = count: 1 sum:100 -st1[1] = count: 1 sum:2 -st2[1] = count: 1 sum:11 -st3[1] = count: 1 sum:101 -st1[2] = count: 1 sum:3 -st2[2] = count: 1 sum:12 -st3[2] = count: 1 sum:102 -st1[3] = count: 1 sum:4 -st2[3] = count: 1 sum:13 -st3[3] = count: 1 sum:103 -st1[4] = count: 1 sum:5 -st2[4] = count: 1 sum:14 -st3[4] = count: 1 sum:104 -st1[5] = count: 1 sum:6 -st2[5] = count: 1 sum:15 -st3[5] = count: 1 sum:105 -st1[6] = count: 1 sum:7 -st2[6] = count: 1 sum:16 -st3[6] = count: 1 sum:106 -st1[7] = count: 1 sum:8 -st2[7] = count: 1 sum:17 -st3[7] = count: 1 sum:107 --------------------- -CPU: 0 Count: 1 Sum: 1 -CPU: 1 Count: 1 Sum: 2 -CPU: 2 Count: 1 Sum: 3 -CPU: 3 Count: 1 Sum: 4 -CPU: 4 Count: 1 Sum: 5 -CPU: 5 Count: 1 Sum: 6 -CPU: 6 Count: 1 Sum: 7 -CPU: 7 Count: 1 Sum: 8 -CPU: 0 Count: 1 Sum: 10 -CPU: 1 Count: 1 Sum: 11 -CPU: 2 Count: 1 Sum: 12 -CPU: 3 Count: 1 Sum: 13 -CPU: 4 Count: 1 Sum: 14 -CPU: 5 Count: 1 Sum: 15 -CPU: 6 Count: 1 Sum: 16 -CPU: 7 Count: 1 Sum: 17 -CPU: 0 Count: 1 Sum: 100 -CPU: 1 Count: 1 Sum: 101 -CPU: 2 Count: 1 Sum: 102 -CPU: 3 Count: 1 Sum: 103 -CPU: 4 Count: 1 Sum: 104 -CPU: 5 Count: 1 Sum: 105 -CPU: 6 Count: 1 Sum: 106 -CPU: 7 Count: 1 Sum: 107 --------------------- -Count: 8 Sum: 36 -Count: 8 Sum: 108 -Count: 8 Sum: 828 --------------------- -count:8 sum:36 avg:4 min:1 max:8 - -count:8 sum:108 avg:13 min:10 max:17 -value |-------------------------------------------------- count - 2 | 0 - 4 | 0 - 8 |@@@@@@ 6 - 16 |@@ 2 - 32 | 0 - -count:8 sum:828 avg:103 min:100 max:107 -value |-------------------------------------------------- count - 85 | 0 - 90 | 0 - 95 |@@@@@@@@ 8 - -count:0 sum:0 avg:0 min:0 max:0 - -count:0 sum:0 avg:0 min:0 max:0 -value |-------------------------------------------------- count - 0 | 0 - 1 | 0 - 2 | 0 - -count:0 sum:0 avg:0 min:0 max:0 -value |-------------------------------------------------- count - 0 | 0 - 5 | 0 - 10 | 0 -} - - -exec rm test - -cleanupTests diff --git a/runtime/tests/agg/all.tcl b/runtime/tests/agg/all.tcl deleted file mode 100644 index 23757202..00000000 --- a/runtime/tests/agg/all.tcl +++ /dev/null @@ -1,4 +0,0 @@ -package require tcltest -namespace import -force tcltest::* -tcltest::testsDirectory [file dir [info script]] -tcltest::runAllTests diff --git a/runtime/tests/agg/count.c b/runtime/tests/agg/count.c deleted file mode 100644 index 8e674d1e..00000000 --- a/runtime/tests/agg/count.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "runtime.h" - -/* test of Counters */ -#include "counter.c" - -int main () -{ - int i; - Counter cnt1 = _stp_counter_init(); - Counter cnt2 = _stp_counter_init(); - - /* testing _stp_counter_add(). These will only be correct if _stp_counter_init() */ - /* set all values to 0 and add works properly. */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_counter_add (cnt1, _processor_number + 1); - _stp_counter_add (cnt2, _processor_number + 10); - } - - /* testing _stp_counter_get_cpu() */ - for (i = 0; i < NR_CPUS; i++) { - printf ("cnt1[%d] = %lld\n", i, _stp_counter_get_cpu(cnt1, i, 0)); - printf ("cnt2[%d] = %lld\n", i, _stp_counter_get_cpu(cnt2, i, 0)); - } - - /* testing _stp_counter_get() */ - printf ("cnt1 = %d\n", _stp_counter_get(cnt1, 0)); - printf ("cnt2 = %d\n", _stp_counter_get(cnt2, 0)); - printf ("--------------------\n"); - - /* testing _stp_counter_add() */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_counter_add (cnt1, _processor_number + 1); - _stp_counter_add (cnt2, _processor_number + 10); - } - - for (i = 0; i < NR_CPUS; i++) { - printf ("cnt1[%d] = %lld\n", i, _stp_counter_get_cpu(cnt1, i, 0)); - printf ("cnt2[%d] = %lld\n", i, _stp_counter_get_cpu(cnt2, i, 0)); - } - printf ("cnt1 = %d\n", _stp_counter_get(cnt1, 1)); - printf ("cnt2 = %d\n", _stp_counter_get(cnt2, 1)); - - printf ("--------------------\n"); - - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_counter_add (cnt1, _processor_number * _processor_number); - _stp_counter_add (cnt2, _processor_number * _processor_number * _processor_number); - } - - printf ("cnt1 = %d\n", _stp_counter_get(cnt1, 1)); - printf ("cnt2 = %d\n", _stp_counter_get(cnt2, 1)); - printf ("cnt1 = %d\n", _stp_counter_get(cnt1, 0)); - printf ("cnt2 = %d\n", _stp_counter_get(cnt2, 0)); - printf ("--------------------\n"); - - - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_counter_add (cnt1, _processor_number * _processor_number); - _stp_counter_add (cnt2, _processor_number * _processor_number * _processor_number); - } - - for (i = 0; i < NR_CPUS; i++) { - printf ("cnt1[%d] = %lld\n", i, _stp_counter_get_cpu(cnt1, i, 0)); - printf ("cnt2[%d] = %lld\n", i, _stp_counter_get_cpu(cnt2, i, 0)); - } - printf ("cnt1 = %d\n", _stp_counter_get(cnt1, 0)); - printf ("cnt2 = %d\n", _stp_counter_get(cnt2, 0)); - - _stp_counter_free (cnt1); - _stp_counter_free (cnt2); - return 0; -} diff --git a/runtime/tests/agg/stats.c b/runtime/tests/agg/stats.c deleted file mode 100644 index 58fb9d41..00000000 --- a/runtime/tests/agg/stats.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "runtime.h" - -/* test of Stats */ -#include "stat.c" - -int main () -{ - int i; - struct stat_data *st; - Stat st1 = _stp_stat_init(HIST_NONE); - Stat st2 = _stp_stat_init(HIST_LOG, 7); - Stat st3 = _stp_stat_init(HIST_LINEAR, 0, 100, 5); - - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_stat_add (st1, _processor_number + 1); - _stp_stat_add (st2, _processor_number + 10); - _stp_stat_add (st3, _processor_number + 100); - } - _processor_number = 0; - - /* this is for internal testing only. Not recommended */ - for (i = 0; i < NR_CPUS; i++) { - st = _stp_stat_get_cpu(st1, i); - printf ("st1[%d] = count: %lld sum:%lld\n", i, st->count, st->sum); - STAT_UNLOCK(st1); - st = _stp_stat_get_cpu(st2, i); - printf ("st2[%d] = count: %lld sum:%lld\n", i, st->count, st->sum); - STAT_UNLOCK(st2); - st = _stp_stat_get_cpu(st3, i); - printf ("st3[%d] = count: %lld sum:%lld\n", i, st->count, st->sum); - STAT_UNLOCK(st3); - } - _stp_printf ("--------------------\n"); - - /* normal way to print per-cpu stats */ - _stp_stat_print_cpu (st1, "CPU: %c\tCount: %C\tSum: %S", 0); - _stp_stat_print_cpu (st2, "CPU: %c\tCount: %C\tSum: %S", 0); - _stp_stat_print_cpu (st3, "CPU: %c\tCount: %C\tSum: %S", 0); - printf ("--------------------\n"); - - /* basic aggregated stats */ - _stp_stat_print (st1, "Count: %C\tSum: %S", 0); - _stp_stat_print (st2, "Count: %C\tSum: %S", 0); - _stp_stat_print (st3, "Count: %C\tSum: %S", 0); - printf ("--------------------\n"); - - /* now print full stats */ - _stp_stat_print (st1, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - _stp_stat_print (st2, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - _stp_stat_print (st3, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - - /* and print again, after they were cleared */ - _stp_stat_print (st1, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - _stp_stat_print (st2, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - _stp_stat_print (st3, "count:%C sum:%S avg:%A min:%m max:%M\n%H", 1); - - _stp_print_flush(); - _stp_stat_del(st1); - _stp_stat_del(st2); - _stp_stat_del(st3); - return 0; -} diff --git a/runtime/tests/all.tcl b/runtime/tests/all.tcl deleted file mode 100644 index f820c588..00000000 --- a/runtime/tests/all.tcl +++ /dev/null @@ -1,12 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -puts "Running all SystemTap tests" - -#puts [tcltest::configure] -#puts [tcltest::configure -file] - - -tcltest::runAllTests - -puts "All tests completed" diff --git a/runtime/tests/maps/Makefile b/runtime/tests/maps/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/maps/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/maps/README b/runtime/tests/maps/README deleted file mode 100644 index 3ff31703..00000000 --- a/runtime/tests/maps/README +++ /dev/null @@ -1,4 +0,0 @@ -Read ../README first! - -The *.c files test associative arrays (maps). "make tests" to run. - diff --git a/runtime/tests/maps/all.tcl b/runtime/tests/maps/all.tcl deleted file mode 100644 index c0b38a0e..00000000 --- a/runtime/tests/maps/all.tcl +++ /dev/null @@ -1,5 +0,0 @@ -package require tcltest -namespace import -force tcltest::* -tcltest::testsDirectory [file dir [info script]] -tcltest::runAllTests - diff --git a/runtime/tests/maps/ii.c b/runtime/tests/maps/ii.c deleted file mode 100644 index 51b0d766..00000000 --- a/runtime/tests/maps/ii.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of int64 and value of int64 */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP map = _stp_map_new_ii(4); - int64_t x; - - dbug("Hello World\n"); - - /* map[1] = 2 */ - _stp_map_set_ii(map, 1, 2); - x = _stp_map_get_ii(map, 1); - printf ("map[1]=%lld\n", x); - - /* map[3] = 4 */ - _stp_map_set_ii(map, 3, 4); - _stp_map_print(map,"map[%1d] = %d"); - - /* now try to confuse things */ - /* These won't do anything useful, but shouldn't crash */ - _stp_map_set_ii(0,1,100); - _stp_map_set_ii(map,0,0); - _stp_map_set_ii(map,100,0); - _stp_map_print(map,"map[%1d] = %d"); - - /* check that unset values are 0 */ - printf ("%lld (should be 0)\n", _stp_map_get_ii(map, 5)); - - /* map[5] = 6 */ - _stp_map_set_ii(map, 5, 6); - _stp_map_print(map,"map[%1d] = %d"); - - /* set wrap */ - map->wrap = 1; - /* add 4 new entries, pushing the others out */ - int i, res; - for (i = 6; i < 10; i++) { - res = _stp_map_set_ii (map, i, 100 + i); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - _stp_map_print(map,"map[%1d] = %d"); - - /* turn off wrap and repeat */ - map->wrap = 0; - for (i = 16; i < 20; i++) { - res = _stp_map_set_ii (map, i, 100 + i); - if (res != -1) - printf("WARNING: During wrap test, got result of %d when expected -1\n", res); - } - - map->wrap = 1; - - /* 5, 382, 526, and 903 all hash to the same value (23) */ - /* use them to test the hash chain */ - _stp_map_set_ii (map, 5, 1005); - _stp_map_set_ii (map, 382, 1382); - _stp_map_set_ii (map, 526, 1526); - _stp_map_set_ii (map, 903, 1903); - _stp_map_print(map,"map[%1d] = %d"); - - - /* now delete all 4 nodes, one by one */ - _stp_map_set_ii (map, 382, 0); - _stp_map_print(map,"map[%1d] = %d"); - - _stp_map_set_ii (map, 5, 0); - _stp_map_print(map,"map[%1d] = %d"); - - _stp_map_set_ii (map, 903, 0); - _stp_map_print(map,"map[%1d] = %d"); - - _stp_map_set_ii (map, 526, 0); - _stp_map_print(map,"map[%1d] = %d"); - - /* finally check clearing the map */ - for (i = 33; i < 77; i+=11) - _stp_map_set_ii (map, i, 100*i+i); - - _stp_map_print(map,"map[%1d] = %d"); - - _stp_map_clear(map); - _stp_map_print(map,"map[%1d] = %d"); - _stp_map_set_ii (map, 1970, 1799); - _stp_map_print(map,"map[%1d] = %d"); - - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/iiiiii.c b/runtime/tests/maps/iiiiii.c deleted file mode 100644 index a5eeef70..00000000 --- a/runtime/tests/maps/iiiiii.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "runtime.h" - -/* test of maps with 5 keys of int64 and value of int64 */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE INT64 -#define KEY4_TYPE INT64 -#define KEY5_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -int main () -{ - struct map_node *ptr; - MAP map = _stp_map_new_iiiiii(4); - - _stp_map_set_iiiiii (map,1,2,3,4,5, 10); - _stp_map_set_iiiiii (map,10,20,30,40,50, 100); - _stp_map_set_iiiiii (map,-1,-2,-3,-4,-5, -10); - _stp_map_set_iiiiii (map,100,200,300,400,500, 1000); - - foreach (map, ptr) - printf ("map[%lld, %lld, %lld, %lld, %lld] = %lld\n", - _stp_key_get_int64(ptr,1), - _stp_key_get_int64(ptr,2), - _stp_key_get_int64(ptr,3), - _stp_key_get_int64(ptr,4), - _stp_key_get_int64(ptr,5), - _stp_get_int64(ptr)); - - _stp_map_print(map,"%1d - %2d - %3d - %4d - %5d *** %d"); - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/iiss.c b/runtime/tests/maps/iiss.c deleted file mode 100644 index 96369d56..00000000 --- a/runtime/tests/maps/iiss.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of int64,int64,string and value of string */ -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP map = _stp_map_new_iiss(4); - map->wrap = 1; - - _stp_map_set_iiss (map, 1,2,"Ohio", "Columbus" ); - _stp_map_set_iiss (map, 3,4,"California", "Sacramento" ); - _stp_map_set_iiss (map, 5,6,"Washington", "Seattle" ); - _stp_map_set_iiss (map, 7,8,"Oregon", "Salem" ); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - _stp_map_set_iiss (map, -9,-10,"Nevada", "Carson City" ); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - _stp_map_set_iiss (map, 5,6,"Washington", "Olymp" ); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - _stp_map_add_iiss (map, 5,6,"Washington", "is" ); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - _stp_map_set_iiss (map, 5,6,"Washington", "Olympia" ); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - /* delete */ - _stp_map_set_iiss (map, -9,-10,"Nevada", 0); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - /* should add nothing */ - _stp_map_set_iiss(map, 0,0,"", ""); - _stp_map_print (map, "map[%1d, %2d, %3s] = %s"); - - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/is.c b/runtime/tests/maps/is.c deleted file mode 100644 index 3008f702..00000000 --- a/runtime/tests/maps/is.c +++ /dev/null @@ -1,119 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of int64 and value of string */ -#define KEY1_TYPE INT64 -#define VALUE_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP map = _stp_map_new_is(4); - map->wrap = 1; - - /* map[1] = one */ - _stp_map_set_is (map, 1, "one"); - - printf ("map[1]=%s\n", _stp_map_get_is(map,1)); - _stp_map_print(map,"map[%1d] = %s"); - - /* map[3] = "three" */ - _stp_map_set_is (map, 3, "three"); - _stp_map_print(map,"map[%1d] = %s"); - - /* now try to confuse things */ - /* These won't do anything useful, but shouldn't crash */ - _stp_map_set_is(0,1,"foobar"); - _stp_map_set_is(map,0,0); - _stp_map_set_is(map,100,0); - _stp_map_print(map,"map[%1d] = %s"); - - /* create and delete a key */ - _stp_map_set_is (map, 1024, "2048"); - _stp_map_set_is (map, 1024, 0); - _stp_map_print(map,"map[%1d] = %s"); - - /* create and delete a key again*/ - _stp_map_set_is (map, 1024, "2048"); - _stp_map_print(map,"map[%1d] = %s"); - _stp_map_set_is (map, 1024, 0); - _stp_map_print(map,"map[%1d] = %s"); - - - /* check that unset values are "" */ - if (*_stp_map_get_is(map, 5)) - printf("ERROR: unset key has nonempty value\n"); - - /* map[5] = "five" */ - _stp_map_set_is (map, 5, "five"); - _stp_map_print(map,"map[%1d] = %s"); - - /* test empty string (should delete)*/ - _stp_map_set_is (map, 5, ""); - _stp_map_print(map,"map[%1d] = %s"); - - - /* add 4 new entries, pushing the others out */ - int i; - for (i = 6; i < 10; i++) - { - char buf[32]; - sprintf(buf, "value of %d", i); - _stp_map_set_is (map, i, buf); - } - _stp_map_print(map,"map[%1d] = %s"); - - /* 5, 382, 526, and 903 all hash to the same value (23) */ - /* use them to test the hash chain */ - _stp_map_set_is (map, 5, "1005"); - _stp_map_set_is (map, 382, "1382"); - _stp_map_set_is (map, 526, "1526"); - _stp_map_set_is (map, 903, "1903"); - - _stp_map_print(map,"map[%1d] = %s"); - - /* now delete all 4 nodes, one by one */ - _stp_map_set_is (map, 382, 0); - _stp_map_print(map,"map[%1d] = %s"); - - _stp_map_set_is (map, 5, 0); - _stp_map_print(map,"map[%1d] = %s"); - - _stp_map_set_is (map, 903, 0); - _stp_map_print(map,"map[%1d] = %s"); - - _stp_map_set_is (map, 526, 0); - _stp_map_print(map,"map[%1d] = %s"); - - /* test overflow errors */ - map->wrap = 0; - for (i = 6; i < 10; i++) - { - char buf[32]; - sprintf(buf, "value of %d", i); - _stp_map_set_is (map, i, buf); - } - - for (i = 6; i < 10; i++) - { - char buf[32]; - int res; - sprintf(buf, "new value of %d", i); - res = _stp_map_set_is (map, i, buf); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - for (i = 16; i < 20; i++) - { - char buf[32]; - int res; - sprintf(buf, "BAD value of %d", i); - res = _stp_map_set_is (map, i, buf); - if (res != -1) - printf("WARNING: During wrap test, got result of %d when expected -1\n", res); - } - _stp_map_print(map,"map[%1d] = %s"); - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/issii.c b/runtime/tests/maps/issii.c deleted file mode 100644 index 4861428a..00000000 --- a/runtime/tests/maps/issii.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of int64,string.string.int64 and value of int64 */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#define KEY2_TYPE STRING -#define KEY3_TYPE STRING -#define KEY4_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -int main () -{ - struct map_node *ptr; - MAP map = _stp_map_new_issii(4); - - _stp_map_set_issii (map, 1, "Boston", "MA", 1970, 5224303 ); - _stp_map_set_issii (map, 2, "Boston", "MA", 2000, 6057826 ); - _stp_map_set_issii (map, 3, "Chicago", "IL", 2000, 8272768 ); - - foreach (map, ptr) - printf ("map[%lld, %s, %s, %lld] = %lld\n", - key1int(ptr), - key2str(ptr), - _stp_key_get_str(ptr,3), - _stp_key_get_int64(ptr,4), - _stp_get_int64(ptr)); - - - _stp_map_print(map,"%1d. The population of %2s, %3s in %4d was %d"); - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/isx.c b/runtime/tests/maps/isx.c deleted file mode 100644 index 9003f522..00000000 --- a/runtime/tests/maps/isx.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of int64 and value of stat */ -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "map-gen.c" -#include "map.c" - -int main () -{ - int i, j; - MAP map = _stp_map_new_ix (4, HIST_LINEAR, 0, 100, 10 ); - MAP map2 = _stp_map_new_ix(4, HIST_LOG, 11); - - for (i = 0; i < 100; i++) - for (j = 0; j <= i*10 ; j++ ) - _stp_map_add_ix (map, 3, i); - - for (i = 0; i < 10; i++) - for (j = 0; j < 10 ; j++ ) - _stp_map_add_ix (map, 2, j * i ); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/10 ; j++ ) - _stp_map_add_ix (map, 1, i); - - for (i = 0; i < 128; i++) - for (j = 0; j < 128 ; j++ ) - _stp_map_add_ix (map2, 1, i); - - for (i = 0; i < 1024; i++) - for (j = 0; j < 1024 ; j++ ) - _stp_map_add_ix (map2, 2, i); - - _stp_map_print (map, "map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - _stp_map_print (map2, "map2[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_map_del (map); - _stp_map_del (map2); - return 0; -} diff --git a/runtime/tests/maps/map.test b/runtime/tests/maps/map.test deleted file mode 100644 index 51feca41..00000000 --- a/runtime/tests/maps/map.test +++ /dev/null @@ -1,999 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -cd $tcltest::testsDirectory - -set CFLAGS "-Os" -set KPATH "/lib/modules/[exec uname -r]/build/include" -set MPATH "/lib/modules/[exec uname -r]/build/include/asm/mach-default" -set PATH "../../user" - -test isx {Test of int64 keys and stat values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test isx.c -} -body { - exec ./test -} -result {map[3] = count:49600 sum:3288450 avg:66 min:0 max:99 -value |-------------------------------------------------- count - 0 |@@ 460 - 10 |@@@@@@@ 1460 - 20 |@@@@@@@@@@@@ 2460 - 30 |@@@@@@@@@@@@@@@@@@ 3460 - 40 |@@@@@@@@@@@@@@@@@@@@@@@ 4460 - 50 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5460 - 60 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6460 - 70 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7460 - 80 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8460 - 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9460 - -map[2] = count:100 sum:2025 avg:20 min:0 max:81 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 42 - 10 |@@@@@@@@@@@@@@@@@ 17 - 20 |@@@@@@@@@@@@@ 13 - 30 |@@@@@@@@@ 9 - 40 |@@@@@@@@@ 9 - 50 |@@@@ 4 - 60 |@@@ 3 - 70 |@@ 2 - 80 |@ 1 - 90 | 0 - -map[1] = count:45 sum:2850 avg:63 min:10 max:90 -value |-------------------------------------------------- count - 0 | 0 - 10 |@ 1 - 20 |@@ 2 - 30 |@@@ 3 - 40 |@@@@ 4 - 50 |@@@@@ 5 - 60 |@@@@@@ 6 - 70 |@@@@@@@ 7 - 80 |@@@@@@@@ 8 - 90 |@@@@@@@@@ 9 - - -map2[1] = count:16384 sum:1040384 avg:63 min:0 max:127 -value |-------------------------------------------------- count - 0 | 128 - 1 | 128 - 2 |@ 256 - 4 |@@@ 512 - 8 |@@@@@@ 1024 - 16 |@@@@@@@@@@@@ 2048 - 32 |@@@@@@@@@@@@@@@@@@@@@@@@ 4096 - 64 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8192 - 128 | 0 - 256 | 0 - -map2[2] = count:1048576 sum:536346624 avg:511 min:0 max:1023 -value |-------------------------------------------------- count - 0 | 1024 - 1 | 1024 - 2 | 2048 - 4 | 4096 - 8 | 8192 - 16 |@ 16384 - 32 |@@@ 32768 - 64 |@@@@@@ 65536 - 128 |@@@@@@@@@@@@ 131072 - 256 |@@@@@@@@@@@@@@@@@@@@@@@@ 262144 - 512 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 524288 - -} - - -test map_format {Torture test of map formatting} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test map_format.c -} -body { - exec ./test -} -result {Columbus -> mapiis 1 2 Ohio -Sacramento -> mapiis 3 4 California -Olympia -> mapiis 5 6 Washington -Salem -> mapiis 7 8 Oregon - -Columbus % Ohio -Sacramento % California -Olympia % Washington -Salem % Oregon - -Columbus -> mapiis -Sacramento -> mapiis -Olympia -> mapiis -Salem -> mapiis - -The capitol of Riga is Latvia and the nerd population is 212063400820736 -The capitol of Sofia is Bulgaria and the nerd population is -2400999087387945352 -The capitol of Valletta is Malta and the nerd population is 1 -The capitol of Nicosia is Cyprus and the nerd population is -1 - -The capitol of Riga is Latvia and the nerd population is c0dedbad0000 -The capitol of Sofia is Bulgaria and the nerd population is deadf00d12345678 -The capitol of Valletta is Malta and the nerd population is 1 -The capitol of Nicosia is Cyprus and the nerd population is ffffffffffffffff - -The capitol of Riga is Latvia and the nerd population is C0DEDBAD0000 -The capitol of Sofia is Bulgaria and the nerd population is DEADF00D12345678 -The capitol of Valletta is Malta and the nerd population is 1 -The capitol of Nicosia is Cyprus and the nerd population is FFFFFFFFFFFFFFFF - -Bogons per packet for Riga -count:49600 sum:3288450 avg:66 min:0 max:99 -value |-------------------------------------------------- count - 0 |@@ 460 - 10 |@@@@@@@ 1460 - 20 |@@@@@@@@@@@@ 2460 - 30 |@@@@@@@@@@@@@@@@@@ 3460 - 40 |@@@@@@@@@@@@@@@@@@@@@@@ 4460 - 50 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5460 - 60 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6460 - 70 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7460 - 80 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8460 - 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9460 - -Bogons per packet for Sofia -count:100 sum:2025 avg:20 min:0 max:81 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 42 - 10 |@@@@@@@@@@@@@@@@@ 17 - 20 |@@@@@@@@@@@@@ 13 - 30 |@@@@@@@@@ 9 - 40 |@@@@@@@@@ 9 - 50 |@@@@ 4 - 60 |@@@ 3 - 70 |@@ 2 - 80 |@ 1 - 90 | 0 - -Bogons per packet for Valletta -count:45 sum:2850 avg:63 min:10 max:90 -value |-------------------------------------------------- count - 0 | 0 - 10 |@ 1 - 20 |@@ 2 - 30 |@@@ 3 - 40 |@@@@ 4 - 50 |@@@@@ 5 - 60 |@@@@@@ 6 - 70 |@@@@@@@ 7 - 80 |@@@@@@@@ 8 - 90 |@@@@@@@@@ 9 - - -49600 was the count for Riga, Latvia -100 was the count for Sofia, Bulgaria -45 was the count for Valletta, Malta - -mapsst[ Riga, Latvia] = 322D82 -mapsst[ Sofia, Bulgaria] = 7E9 -mapsst[ Valletta, Malta] = B22} - -test map_issii {Test of int64,string,string,int64 keys and int64 values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test issii.c -} -body { - exec ./test -} -result {map[1, Boston, MA, 1970] = 5224303 -map[2, Boston, MA, 2000] = 6057826 -map[3, Chicago, IL, 2000] = 8272768 -1. The population of Boston, MA in 1970 was 5224303 -2. The population of Boston, MA in 2000 was 6057826 -3. The population of Chicago, IL in 2000 was 8272768 -} - -test map_sort {Test of sorting} -setup { - puts "gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test sort.c" - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test sort.c -} -body { - exec ./test -} -result {sorting from A-Z on value -Boston -> 5 5 Massachusetts -Carson City -> 7 8 Nevada -Columbus -> 1 2 Ohio -Des Moines -> 8 8 Iowa -Montpelier -> 2 2 Vermont -Olympia -> 5 6 Washington -Raleigh -> -1 9 North Carolina -Sacramento -> 3 4 California -Salem -> 7 8 Oregon -Santa Fe -> 1 4 New Mexico - - -sorting from Z-A on value -Santa Fe -> 1 4 New Mexico -Salem -> 7 8 Oregon -Sacramento -> 3 4 California -Raleigh -> -1 9 North Carolina -Olympia -> 5 6 Washington -Montpelier -> 2 2 Vermont -Des Moines -> 8 8 Iowa -Columbus -> 1 2 Ohio -Carson City -> 7 8 Nevada -Boston -> 5 5 Massachusetts - - -sorting from low to high on key 1 --1 9 North Carolina -> Raleigh -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus -2 2 Vermont -> Montpelier -3 4 California -> Sacramento -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -8 8 Iowa -> Des Moines - - -sorting from high to low on key 1 -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -3 4 California -> Sacramento -2 2 Vermont -> Montpelier -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus --1 9 North Carolina -> Raleigh - - -sorting from low to high on key 2 -2 2 Vermont -> Montpelier -1 2 Ohio -> Columbus -3 4 California -> Sacramento -1 4 New Mexico -> Santa Fe -5 5 Massachusetts -> Boston -5 6 Washington -> Olympia -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City --1 9 North Carolina -> Raleigh - - -sorting from high to low on key 2 --1 9 North Carolina -> Raleigh -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -3 4 California -> Sacramento -1 4 New Mexico -> Santa Fe -2 2 Vermont -> Montpelier -1 2 Ohio -> Columbus - - -sorting from low to high on key 3 -California 3 4 -> Sacramento -Iowa 8 8 -> Des Moines -Massachusetts 5 5 -> Boston -Nevada 7 8 -> Carson City -New Mexico 1 4 -> Santa Fe -North Carolina -1 9 -> Raleigh -Ohio 1 2 -> Columbus -Oregon 7 8 -> Salem -Vermont 2 2 -> Montpelier -Washington 5 6 -> Olympia - - -sorting from high to low on key 3 -Washington 5 6 -> Olympia -Vermont 2 2 -> Montpelier -Oregon 7 8 -> Salem -Ohio 1 2 -> Columbus -North Carolina -1 9 -> Raleigh -New Mexico 1 4 -> Santa Fe -Nevada 7 8 -> Carson City -Massachusetts 5 5 -> Boston -Iowa 8 8 -> Des Moines -California 3 4 -> Sacramento - - -top 3 alphabetical by value -Boston -> 5 5 Massachusetts -Carson City -> 7 8 Nevada -Columbus -> 1 2 Ohio - - -bottom 2 alphabetical by value -Santa Fe -> 1 4 New Mexico -Salem -> 7 8 Oregon - - -top 5 sorted by key 1 -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston - - -bottom 5 sorted by key 1 --1 9 North Carolina -> Raleigh -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus -2 2 Vermont -> Montpelier -3 4 California -> Sacramento - -sorted by population from low to high -Nicosia is the capitol of Cyprus and the nerd population is -1 -Valletta is the capitol of Malta and the nerd population is 1 -Riga is the capitol of Latvia and the nerd population is 135786 -Sofia is the capitol of Bulgaria and the nerd population is 138740 - -sorted by population from high to low -Sofia is the capitol of Bulgaria and the nerd population is 138740 -Riga is the capitol of Latvia and the nerd population is 135786 -Valletta is the capitol of Malta and the nerd population is 1 -Nicosia is the capitol of Cyprus and the nerd population is -1 -} - -test ii {Test of int64 keys and int64 values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ii.c -} -body { - exec ./test -} -result {map[1]=2 -map[1] = 2 -map[3] = 4 - -map[1] = 2 -map[3] = 4 - -0 (should be 0) -map[1] = 2 -map[3] = 4 -map[5] = 6 - -map[6] = 106 -map[7] = 107 -map[8] = 108 -map[9] = 109 - -map[5] = 1005 -map[382] = 1382 -map[526] = 1526 -map[903] = 1903 - -map[5] = 1005 -map[526] = 1526 -map[903] = 1903 - -map[526] = 1526 -map[903] = 1903 - -map[526] = 1526 - - -map[33] = 3333 -map[44] = 4444 -map[55] = 5555 -map[66] = 6666 - - -map[1970] = 1799 -} - -test is {Test of int64 keys and string values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test is.c -} -body { - exec ./test -} -result {map[1]=one -map[1] = one - -map[1] = one -map[3] = three - -map[1] = one -map[3] = three - -map[1] = one -map[3] = three - -map[1] = one -map[3] = three -map[1024] = 2048 - -map[1] = one -map[3] = three - -map[1] = one -map[3] = three -map[5] = five - -map[1] = one -map[3] = three - -map[6] = value of 6 -map[7] = value of 7 -map[8] = value of 8 -map[9] = value of 9 - -map[5] = 1005 -map[382] = 1382 -map[526] = 1526 -map[903] = 1903 - -map[5] = 1005 -map[526] = 1526 -map[903] = 1903 - -map[526] = 1526 -map[903] = 1903 - -map[526] = 1526 - - -map[6] = new value of 6 -map[7] = new value of 7 -map[8] = new value of 8 -map[9] = new value of 9 -} - -test si {Test of string keys and int64 values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test si.c -} -body { - exec ./test -} -result {map[Ohio]=1 -map[Ohio] = 1 - -map[Ohio] = 1 -map[Washington] = 2 - -map[Ohio] = 1 -map[Washington] = 2 - -map[Ohio] = 1 -map[Washington] = 2 -map[1024] = 2048 - -map[Ohio] = 1 -map[Washington] = 2 - -map[Ohio] = 1 -map[Washington] = 2 -map[1024] = 2048 - -map[Ohio] = 1 -map[Washington] = 2 - -map[Ohio] = 1 -map[Washington] = 2 -map[California] = 3 - -map[Ohio] = 1 -map[Washington] = 2 -map[California] = 3 -map[] = 7777 - -map[Ohio] = 1 -map[Washington] = 2 -map[California] = 3 -map[] = 8888 - -map[Ohio] = 1 -map[Washington] = 2 -map[California] = 3 - -map[String 6] = 106 -map[String 7] = 107 -map[String 8] = 108 -map[String 9] = 109 - -map[String 6] = 106 -map[String 7] = 107 -map[String 8] = 108 -map[String 9] = 109 - -map[String 6] = 6106 -map[String 7] = 7107 -map[String 8] = 8108 -map[String 9] = 9109 - -map[String 6] = 6 -map[String 7] = 7 -map[String 8] = 8 -map[String 9] = 9 - -} - -test iiss {Test of int64,int64,string keys and string values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test iiss.c -} -body { - exec ./test -} -result {map[1, 2, Ohio] = Columbus -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Seattle -map[7, 8, Oregon] = Salem - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Seattle -map[7, 8, Oregon] = Salem -map[-9, -10, Nevada] = Carson City - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Olymp -map[7, 8, Oregon] = Salem -map[-9, -10, Nevada] = Carson City - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Olympis -map[7, 8, Oregon] = Salem -map[-9, -10, Nevada] = Carson City - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Olympia -map[7, 8, Oregon] = Salem -map[-9, -10, Nevada] = Carson City - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Olympia -map[7, 8, Oregon] = Salem - -map[3, 4, California] = Sacramento -map[5, 6, Washington] = Olympia -map[7, 8, Oregon] = Salem -} - -test setadd {Test of setting and adding values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test setadd.c -} -body { - exec ./test -} -result {mapi[1] = 1 -mapi[2] = 4 -mapi[3] = 9 -mapi[4] = 16 - -maps[1] = value of 1 -maps[2] = value of 2 -maps[3] = value of 3 -maps[4] = value of 4 - -mapx[1] = count:1 sum:1 avg:1 min:1 max:1 -mapx[2] = count:1 sum:2 avg:2 min:2 max:2 -mapx[3] = count:1 sum:3 avg:3 min:3 max:3 -mapx[4] = count:1 sum:4 avg:4 min:4 max:4 - -mapi[1] = 2 -mapi[2] = 8 -mapi[3] = 18 -mapi[4] = 32 - -maps[1] = value of 1***** -maps[2] = value of 2***** -maps[3] = value of 3***** -maps[4] = value of 4***** - -mapx[1] = count:2 sum:3 avg:1 min:1 max:2 -mapx[2] = count:2 sum:6 avg:3 min:2 max:4 -mapx[3] = count:2 sum:9 avg:4 min:3 max:6 -mapx[4] = count:2 sum:12 avg:6 min:4 max:8 - -Adding 0 -mapi[1] = 2 -mapi[2] = 8 -mapi[3] = 18 -mapi[4] = 32 - -maps[1] = value of 1***** -maps[2] = value of 2***** -maps[3] = value of 3***** -maps[4] = value of 4***** - -maps[1] = value of 1***** -maps[2] = value of 2***** -maps[3] = value of 3***** -maps[4] = value of 4***** - -mapx[1] = count:3 sum:3 avg:1 min:0 max:2 -mapx[2] = count:3 sum:6 avg:2 min:0 max:4 -mapx[3] = count:3 sum:9 avg:3 min:0 max:6 -mapx[4] = count:3 sum:12 avg:4 min:0 max:8 - -Add 'X' to strings -maps[1] = value of 1*****X -maps[2] = value of 2*****X -maps[3] = value of 3*****X -maps[4] = value of 4*****X - -setting everything to 0 - - - - -Adding 0 - - - -mapx[1] = count:1 sum:0 avg:0 min:0 max:0 -mapx[2] = count:1 sum:0 avg:0 min:0 max:0 -mapx[3] = count:1 sum:0 avg:0 min:0 max:0 -mapx[4] = count:1 sum:0 avg:0 min:0 max:0 - -setting everything to -1 -mapi[1] = -1 -mapi[2] = -1 -mapi[3] = -1 -mapi[4] = -1 - -mapx[1] = count:1 sum:-1 avg:-1 min:-1 max:-1 -mapx[2] = count:1 sum:-1 avg:-1 min:-1 max:-1 -mapx[3] = count:1 sum:-1 avg:-1 min:-1 max:-1 -mapx[4] = count:1 sum:-1 avg:-1 min:-1 max:-1 - -adding -1 -mapi[1] = -2 -mapi[2] = -2 -mapi[3] = -2 -mapi[4] = -2 - -mapx[1] = count:2 sum:-2 avg:-1 min:-1 max:-1 -mapx[2] = count:2 sum:-2 avg:-1 min:-1 max:-1 -mapx[3] = count:2 sum:-2 avg:-1 min:-1 max:-1 -mapx[4] = count:2 sum:-2 avg:-1 min:-1 max:-1 -} - -test iiiiii {Test of 5 int keys and an int value} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test iiiiii.c -} -body { - exec ./test -} -result {map[1, 2, 3, 4, 5] = 10 -map[10, 20, 30, 40, 50] = 100 -map[-1, -2, -3, -4, -5] = -10 -map[100, 200, 300, 400, 500] = 1000 -1 - 2 - 3 - 4 - 5 *** 10 -10 - 20 - 30 - 40 - 50 *** 100 --1 - -2 - -3 - -4 - -5 *** -10 -100 - 200 - 300 - 400 - 500 *** 1000 -} - -test ssssss {Test of 5 string keys and a string value} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ssssss.c -} -body { - exec ./test -} -result {map[1ABC, 2ABC, 3ABC, 4ABC, 5ABC] = 666 -map[1QRS, 2QRS, 3QRS, 4QRS, 5QRS] = 777 -map[1abc, 2abc, 3abc, 4abc, 5abc] = 888 -map[1XYZ, 2XYZ, 3XYZ, 4XYZ, 5XYZ] = 999 -1ABC and 2ABC and 3ABC and 4ABC and 5ABC ---> 666 -1QRS and 2QRS and 3QRS and 4QRS and 5QRS ---> 777 -1abc and 2abc and 3abc and 4abc and 5abc ---> 888 -1XYZ and 2XYZ and 3XYZ and 4XYZ and 5XYZ ---> 999 -} - -test sort_stat {Test of sorting stats} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test sort_stat.c -} -body { - exec ./test -} -result {Bogons per packet for California -count:49600 sum:3288450 avg:66 min:0 max:99 -value |-------------------------------------------------- count - 0 |@@ 460 - 10 |@@@@@@@ 1460 - 20 |@@@@@@@@@@@@ 2460 - 30 |@@@@@@@@@@@@@@@@@@ 3460 - 40 |@@@@@@@@@@@@@@@@@@@@@@@ 4460 - 50 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5460 - 60 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6460 - 70 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7460 - 80 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8460 - 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9460 - -Bogons per packet for Washington -count:100 sum:2025 avg:20 min:0 max:81 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 42 - 10 |@@@@@@@@@@@@@@@@@ 17 - 20 |@@@@@@@@@@@@@ 13 - 30 |@@@@@@@@@ 9 - 40 |@@@@@@@@@ 9 - 50 |@@@@ 4 - 60 |@@@ 3 - 70 |@@ 2 - 80 |@ 1 - 90 | 0 - -Bogons per packet for Oregon -count:90 sum:5700 avg:63 min:10 max:90 -value |-------------------------------------------------- count - 0 | 0 - 10 |@@ 2 - 20 |@@@@ 4 - 30 |@@@@@@ 6 - 40 |@@@@@@@@ 8 - 50 |@@@@@@@@@@ 10 - 60 |@@@@@@@@@@@@ 12 - 70 |@@@@@@@@@@@@@@ 14 - 80 |@@@@@@@@@@@@@@@@ 16 - 90 |@@@@@@@@@@@@@@@@@@ 18 - -Bogons per packet for Nevada -count:45 sum:2970 avg:66 min:10 max:98 -value |-------------------------------------------------- count - 0 | 0 - 10 |@ 1 - 20 |@@ 2 - 30 |@@@ 3 - 40 |@@@@ 4 - 50 |@@@@@ 5 - 60 |@@@@@@ 6 - 70 |@@@@@@@ 7 - 80 |@@@@@@@@ 8 - 90 |@@@@@@@@@ 9 - -Bogons per packet for Ohio -count:20 sum:1000 avg:50 min:50 max:50 -value |-------------------------------------------------- count - 30 | 0 - 40 | 0 - 50 |@@@@@@@@@@@@@@@@@@@@ 20 - 60 | 0 - 70 | 0 - -Bogons per packet for North Carolina -count:45 sum:-4200 avg:-93 min:-620 max:100 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@ 26 - 10 |@ 1 - 20 |@@ 2 - 30 |@ 1 - 40 |@@ 2 - 50 |@ 1 - 60 |@ 1 - 70 |@ 1 - 80 |@ 1 - 90 |@@@@@@@@@ 9 - -Bogons per packet for New Mexico -count:450 sum:8475 avg:18 min:-39 max:50 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 145 - 10 |@@@@@@@@@@@@@@@@@@@ 59 - 20 |@@@@@@@@@@@@@@@@@@@@@@@ 69 - 30 |@@@@@@@@@@@@@@@@@@@@@@@@@@ 79 - 40 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 89 - 50 |@@@ 9 - 60 | 0 - 70 | 0 - - -SORTED BY COUNT -49600 California -450 New Mexico -100 Washington -90 Oregon -45 Nevada -45 North Carolina -20 Ohio - -SORTED BY COUNT (low to high) -20 Ohio -45 Nevada -45 North Carolina -90 Oregon -100 Washington -450 New Mexico -49600 California - -SORTED BY SUM -3288450 California -8475 New Mexico -5700 Oregon -2970 Nevada -2025 Washington -1000 Ohio --4200 North Carolina - -SORTED BY SUM (low to high) --4200 North Carolina -1000 Ohio -2025 Washington -2970 Nevada -5700 Oregon -8475 New Mexico -3288450 California - -SORTED BY MIN -50 Ohio -10 Nevada -10 Oregon -0 Washington -0 California --39 New Mexico --620 North Carolina - -SORTED BY MIN (low to high) --620 North Carolina --39 New Mexico -0 Washington -0 California -10 Nevada -10 Oregon -50 Ohio - -SORTED BY MAX -100 North Carolina -99 California -98 Nevada -90 Oregon -81 Washington -50 New Mexico -50 Ohio - -SORTED BY MAX (low to high) -50 New Mexico -50 Ohio -81 Washington -90 Oregon -98 Nevada -99 California -100 North Carolina - -SORTED BY AVG -66 Nevada -66 California -63 Oregon -50 Ohio -20 Washington -18 New Mexico --93 North Carolina - -SORTED BY AVG (low to high) --93 North Carolina -18 New Mexico -20 Washington -50 Ohio -63 Oregon -66 Nevada -66 California -} - -test sort2 {Test of sorting (odd number of elements)} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test sort2.c -} -body { - exec ./test -} -result {sorting from A-Z on value -Boston -> 5 5 Massachusetts -Carson City -> 7 8 Nevada -Columbus -> 1 2 Ohio -Des Moines -> 8 8 Iowa -Olympia -> 5 6 Washington -Raleigh -> -1 9 North Carolina -Sacramento -> 3 4 California -Salem -> 7 8 Oregon -Santa Fe -> 1 4 New Mexico - - -sorting from Z-A on value -Santa Fe -> 1 4 New Mexico -Salem -> 7 8 Oregon -Sacramento -> 3 4 California -Raleigh -> -1 9 North Carolina -Olympia -> 5 6 Washington -Des Moines -> 8 8 Iowa -Columbus -> 1 2 Ohio -Carson City -> 7 8 Nevada -Boston -> 5 5 Massachusetts - - -sorting from low to high on key 1 --1 9 North Carolina -> Raleigh -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus -3 4 California -> Sacramento -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -8 8 Iowa -> Des Moines - - -sorting from high to low on key 1 -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -3 4 California -> Sacramento -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus --1 9 North Carolina -> Raleigh - - -sorting from low to high on key 2 -1 2 Ohio -> Columbus -3 4 California -> Sacramento -1 4 New Mexico -> Santa Fe -5 5 Massachusetts -> Boston -5 6 Washington -> Olympia -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City --1 9 North Carolina -> Raleigh - - -sorting from high to low on key 2 --1 9 North Carolina -> Raleigh -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston -3 4 California -> Sacramento -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus - - -sorting from low to high on key 3 -California 3 4 -> Sacramento -Iowa 8 8 -> Des Moines -Massachusetts 5 5 -> Boston -Nevada 7 8 -> Carson City -New Mexico 1 4 -> Santa Fe -North Carolina -1 9 -> Raleigh -Ohio 1 2 -> Columbus -Oregon 7 8 -> Salem -Washington 5 6 -> Olympia - - -sorting from high to low on key 3 -Washington 5 6 -> Olympia -Oregon 7 8 -> Salem -Ohio 1 2 -> Columbus -North Carolina -1 9 -> Raleigh -New Mexico 1 4 -> Santa Fe -Nevada 7 8 -> Carson City -Massachusetts 5 5 -> Boston -Iowa 8 8 -> Des Moines -California 3 4 -> Sacramento - - -top 3 alphabetical by value -Boston -> 5 5 Massachusetts -Carson City -> 7 8 Nevada -Columbus -> 1 2 Ohio - - -bottom 2 alphabetical by value -Santa Fe -> 1 4 New Mexico -Salem -> 7 8 Oregon - - -top 5 sorted by key 1 -8 8 Iowa -> Des Moines -7 8 Oregon -> Salem -7 8 Nevada -> Carson City -5 6 Washington -> Olympia -5 5 Massachusetts -> Boston - - -bottom 5 sorted by key 1 --1 9 North Carolina -> Raleigh -1 4 New Mexico -> Santa Fe -1 2 Ohio -> Columbus -3 4 California -> Sacramento -5 6 Washington -> Olympia - -sorted by population from low to high -Nicosia is the capitol of Cyprus and the nerd population is -1 -Valletta is the capitol of Malta and the nerd population is 1 -Chisinau is the capitol of Moldova and the nerd population is 1024 -Riga is the capitol of Latvia and the nerd population is 135786 -Sofia is the capitol of Bulgaria and the nerd population is 138740 - -sorted by population from high to low -Sofia is the capitol of Bulgaria and the nerd population is 138740 -Riga is the capitol of Latvia and the nerd population is 135786 -Chisinau is the capitol of Moldova and the nerd population is 1024 -Valletta is the capitol of Malta and the nerd population is 1 -Nicosia is the capitol of Cyprus and the nerd population is -1 -} - - -test size {Test of _stp_map_size()} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test size.c -} -body { - exec ./test -} -result {} - -catch {exec rm test} - -cleanupTests diff --git a/runtime/tests/maps/map_format.c b/runtime/tests/maps/map_format.c deleted file mode 100644 index 184aa79a..00000000 --- a/runtime/tests/maps/map_format.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "runtime.h" - -/* torture test of map formatting */ -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE STRING -#include "map-gen.c" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "map-gen.c" - -#define VALUE_TYPE STAT -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP mapiis = _stp_map_new_iiss(4); - _stp_map_set_iiss (mapiis, 1,2,"Ohio", "Columbus" ); - _stp_map_set_iiss (mapiis, 3,4,"California", "Sacramento" ); - _stp_map_set_iiss (mapiis, 5,6,"Washington", "Olympia" ); - _stp_map_set_iiss (mapiis, 7,8,"Oregon", "Salem" ); - _stp_map_print (mapiis, "%s -> mapiis %1d %2d %3s"); - - /* test printing of '%' */ - _stp_map_print (mapiis, "%s %% %3s"); - - /* very bad string. don't crash */ - _stp_map_print (mapiis, "%s -> mapiis %1s %2s %3d %4d"); - - MAP mapss = _stp_map_new_ssi(4); - _stp_map_set_ssi (mapss, "Riga", "Latvia", 0x0000c0dedbad0000LL); - _stp_map_set_ssi (mapss, "Sofia", "Bulgaria", 0xdeadf00d12345678LL); - _stp_map_set_ssi (mapss, "Valletta", "Malta", 1); - _stp_map_set_ssi (mapss, "Nicosia", "Cyprus", -1); - _stp_map_print (mapss, "The capitol of %1s is %2s and the nerd population is %d"); - _stp_map_print (mapss, "The capitol of %1s is %2s and the nerd population is %x"); - _stp_map_print (mapss, "The capitol of %1s is %2s and the nerd population is %X"); - - MAP mapsst = _stp_map_new_ssx (4, HIST_LINEAR, 0, 100, 10 ); - int i,j; - - for (i = 0; i < 100; i++) - for (j = 0; j <= i*10 ; j++ ) - _stp_map_add_ssx (mapsst, "Riga", "Latvia", i); - - for (i = 0; i < 10; i++) - for (j = 0; j < 10 ; j++ ) - _stp_map_add_ssx (mapsst, "Sofia", "Bulgaria", j * i ); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/10 ; j++ ) - _stp_map_add_ssx (mapsst, "Valletta", "Malta", i); - - _stp_map_print (mapsst, "Bogons per packet for %1s\ncount:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_map_print (mapsst, "%C was the count for %1s, %2s"); - - /* here's how to print a map without using _stp_map_print(). */ - struct map_node *ptr; - foreach (mapsst, ptr) - _stp_printf ("mapsst[%09s,%09s] = %llX\n", key1str(ptr), key2str(ptr), _stp_get_stat(ptr)->sum); - _stp_print_flush(); - - return 0; -} diff --git a/runtime/tests/maps/setadd.c b/runtime/tests/maps/setadd.c deleted file mode 100644 index 8eedbaa9..00000000 --- a/runtime/tests/maps/setadd.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "runtime.h" - -/* verify correct set and add behavior */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#define STP_MAP_II -#include "map-gen.c" - -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -int main () -{ - int i, res; - MAP mapi = _stp_map_new_ii(4); - MAP maps = _stp_map_new_is(4); - MAP mapx = _stp_map_new_ix(4, HIST_NONE); - - /* use add to set initial values */ - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ii (mapi, i, i*i); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - char buf[32]; - sprintf(buf, "value of %d", i); - res = _stp_map_add_is (maps, i, buf); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ix (mapx, i, i); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - /*************** now add some values *******************/ - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ii (mapi, i, i*i); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, "*****"); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ix (mapx, i, i+i); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - /*************** now add 0 *******************/ - printf ("Adding 0\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ii (mapi, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, ""); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - /* adding NULL should be same as adding "" for string values */ - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ix (mapx, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - /*************** now add X to strings *******************/ - printf ("Add 'X' to strings\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, "X"); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - /*************** now set to 0 (clear) *******************/ - printf ("setting everything to 0\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_set_ii (mapi, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_set_is (maps, i, ""); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - /* set it back to something */ - for (i = 1; i < 5; i++) - { - char buf[32]; - sprintf(buf, "%d", i); - res = _stp_map_set_is (maps, i, buf); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - - /* setting to NULL also deletes */ - for (i = 1; i < 5; i++) - { - res = _stp_map_set_is (maps, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_set_ix (mapx, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - /*************** now add 0 *******************/ - printf ("Adding 0\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ii (mapi, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_is (maps, i, ""); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(maps,"maps[%1d] = %s"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ix (mapx, i, 0); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - - /*************** now set to -1 *******************/ - printf ("setting everything to -1\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_set_ii (mapi, i, -1); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_set_ix (mapx, i, -1); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - /*************** now add -1 *******************/ - printf ("adding -1\n"); - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ii (mapi, i, -1); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print(mapi,"mapi[%1d] = %d"); - - for (i = 1; i < 5; i++) - { - res = _stp_map_add_ix (mapx, i, -1); - if (res) - printf("ERROR: got result of %d when expected 0\n", res); - } - _stp_map_print (mapx, "mapx[%1d] = count:%C sum:%S avg:%A min:%m max:%M"); - - - _stp_map_del (mapi); - _stp_map_del (maps); - _stp_map_del (mapx); - return 0; -} diff --git a/runtime/tests/maps/si.c b/runtime/tests/maps/si.c deleted file mode 100644 index d9db65d7..00000000 --- a/runtime/tests/maps/si.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys of string and value of int64 */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#include "map-gen.c" -#include "map.c" - -int main () -{ - int res; - MAP map = _stp_map_new_si(4); - map->wrap = 1; - - /* map[Ohio] = 1 */ - _stp_map_set_si (map, "Ohio", 1); - printf ("map[Ohio]=%lld\n", _stp_map_get_si(map,"Ohio")); - _stp_map_print(map,"map[%1s] = %d"); - - /* map[Washington] = 2 */ - _stp_map_set_si (map, "Washington", 2); - _stp_map_print (map, "map[%1s] = %d"); - - /* now try to confuse things */ - /* These won't do anything useful, but shouldn't crash */ - - /* bad map */ - res = _stp_map_set_si(0,"foo",100); - if (res != -2) - printf("WARNING: got result of %d when expected -2\n", res); - - /* bad key */ - res = _stp_map_set_si(map,0,0); - if (res != -2) - printf("WARNING: got result of %d when expected -2\n", res); - - /* bad key */ - res = _stp_map_set_si(map,0,42); - if (res != -2) - printf("WARNING: got result of %d when expected -2\n", res); - - res = _stp_map_set_si(map,"",0); - if (res) - printf("WARNING: got result of %d when expected 0\n", res); - _stp_map_print (map, "map[%1s] = %d"); - - /* create and delete a key */ - _stp_map_set_si (map, "1024", 2048); - _stp_map_print (map, "map[%1s] = %d"); - _stp_map_set_si (map, "1024", 0); - _stp_map_print (map, "map[%1s] = %d"); - _stp_map_set_si (map, "1024", 2048); - _stp_map_print (map, "map[%1s] = %d"); - _stp_map_set_si (map, "1024", 0); - _stp_map_print (map, "map[%1s] = %d"); - - /* check that unset values are 0 */ - res = _stp_map_get_si (map, "California"); - if (res) - printf("ERROR: map[California] = %d (should be 0)\n", res); - - /* map[California] = 3 */ - _stp_map_set_si (map, "California", 3); - _stp_map_print (map, "map[%1s] = %d"); - - /* test an empty string as key */ - _stp_map_set_si (map, "", 7777); - _stp_map_print (map, "map[%1s] = %d"); - _stp_map_set_si (map, "", 8888); - _stp_map_print (map, "map[%1s] = %d"); - _stp_map_set_si (map, "", 0); - _stp_map_print (map, "map[%1s] = %d"); - - - /* add 4 new entries, pushing the others out */ - int i; - for (i = 6; i < 10; i++) - { - char buf[32]; - sprintf (buf, "String %d", i); - res = _stp_map_set_si (map, buf, 100 + i); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - _stp_map_print (map, "map[%1s] = %d"); - - /* turn off wrap and repeat */ - map->wrap = 0; - for (i = 16; i < 20; i++) { - char buf[32]; - sprintf (buf, "BAD String %d", i); - res = _stp_map_set_si (map, buf, 100 + i); - if (res != -1) - printf("WARNING: During wrap test, got result of %d when expected -1\n", res); - } - _stp_map_print (map, "map[%1s] = %d"); - - /* test addition */ - for (i = 6; i < 10; i++) - { - char buf[32]; - sprintf (buf, "String %d", i); - res = _stp_map_add_si (map, buf, 1000 * i); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - _stp_map_print (map, "map[%1s] = %d"); - - /* reset all */ - for (i = 6; i < 10; i++) - { - char buf[32]; - sprintf (buf, "String %d", i); - res = _stp_map_set_si (map, buf, i); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - _stp_map_print (map, "map[%1s] = %d"); - - _stp_map_clear(map); - _stp_map_print (map, "map[%1s] = %d"); - - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/size.c b/runtime/tests/maps/size.c deleted file mode 100644 index 2fb2575c..00000000 --- a/runtime/tests/maps/size.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "runtime.h" - -/* test of _stp_map_size() */ -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -#define check(map,num) \ - { \ - int size = _stp_map_size(map); \ - if (size != num) \ - printf("ERROR at line %d: expected size %d and got %d instead.\n", __LINE__, num, size); \ - } - -int main () -{ - MAP map = _stp_map_new_ii(4); - int64_t x; - - check (map, 0); - - /* map[1] = 2 */ - _stp_map_set_ii(map, 1, 2); - check (map, 1); - - /* map[3] = 4 */ - _stp_map_set_ii(map, 3, 4); - check (map,2); - - /* now try to confuse things */ - /* These won't do anything useful, but shouldn't crash */ - _stp_map_set_ii(0,1,100); - _stp_map_set_ii(map,0,0); - _stp_map_set_ii(map,100,0); - check (map,2); - - /* map[5] = 6 */ - _stp_map_set_ii(map, 5, 6); - check (map,3); - - /* set wrap */ - map->wrap = 1; - /* add 4 new entries, pushing the others out */ - int i, res; - for (i = 6; i < 10; i++) { - res = _stp_map_set_ii (map, i, 100 + i); - if (res) - printf("WARNING: During wrap test, got result of %d when expected 0\n", res); - } - check (map,4); - - /* turn off wrap and repeat */ - map->wrap = 0; - for (i = 16; i < 20; i++) { - res = _stp_map_set_ii (map, i, 100 + i); - if (res != -1) - printf("WARNING: During wrap test, got result of %d when expected -1\n", res); - } - check (map,4); - - map->wrap = 1; - - /* 5, 382, 526, and 903 all hash to the same value (23) */ - /* use them to test the hash chain */ - _stp_map_set_ii (map, 5, 1005); - _stp_map_set_ii (map, 382, 1382); - _stp_map_set_ii (map, 526, 1526); - _stp_map_set_ii (map, 903, 1903); - check (map,4); - - /* now delete all 4 nodes, one by one */ - _stp_map_set_ii (map, 382, 0); - check (map,3); - - _stp_map_set_ii (map, 5, 0); - check (map,2); - - _stp_map_set_ii (map, 903, 0); - check (map,1); - - _stp_map_set_ii (map, 526, 0); - check (map,0); - - /* finally check clearing the map */ - _stp_map_clear(map); - check (map,0); - - map->wrap = 0; - for (i = 33; i < 99; i+=11) - _stp_map_set_ii (map, i, 100*i+i); - check (map,4); - - _stp_map_clear(map); - check (map,0); - - _stp_map_set_ii (map, 1970, 1799); - check (map,1); - - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/maps/sort.c b/runtime/tests/maps/sort.c deleted file mode 100644 index 7ae22206..00000000 --- a/runtime/tests/maps/sort.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "runtime.h" - -/* test of map sorting */ -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE STRING -#include "map-gen.c" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP mapiis = _stp_map_new_iiss(10); - - /* try to crash the sorts with sorting an empty list */ - _stp_map_sort (mapiis, 0, -1); - _stp_map_sort (mapiis, 0, 1); - _stp_map_sortn (mapiis, 3, 0, -1); - _stp_map_sortn (mapiis, 0, 0, -1); - - /* load some test data */ - _stp_map_add_iiss (mapiis, 3,4,"California","Sacramento" ); - _stp_map_set_iiss (mapiis, 5,6,"Washington","Olympia" ); - _stp_map_set_iiss (mapiis, 7,8,"Oregon","Salem" ); - _stp_map_set_iiss (mapiis, 7,8,"Nevada","Carson City" ); - _stp_map_set_iiss (mapiis, 1, 4,"New Mexico","Santa Fe" ); - _stp_map_set_iiss (mapiis, -1,9,"North Carolina","Raleigh" ); - _stp_map_set_iiss (mapiis, 5,5,"Massachusetts","Boston" ); - _stp_map_set_iiss (mapiis, 2,2,"Vermont","Montpelier" ); - _stp_map_set_iiss (mapiis, 8,8,"Iowa","Des Moines" ); - _stp_map_set_iiss (mapiis, 1,2,"Ohio","Columbus" ); - - _stp_printf("sorting from A-Z on value\n"); - _stp_map_sort (mapiis, 0, -1); - _stp_map_print (mapiis, "%s -> %1d %2d %3s"); - - _stp_printf("\nsorting from Z-A on value\n"); - _stp_map_sort (mapiis, 0, 1); - _stp_map_print (mapiis, "%s -> %1d %2d %3s"); - - _stp_printf("\nsorting from low to high on key 1\n"); - _stp_map_sort (mapiis, 1, -1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from high to low on key 1\n"); - _stp_map_sort (mapiis, 1, 1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from low to high on key 2\n"); - _stp_map_sort (mapiis, 2, -1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from high to low on key 2\n"); - _stp_map_sort (mapiis, 2, 1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - - _stp_printf("\nsorting from low to high on key 3\n"); - _stp_map_sort (mapiis, 3, -1); - _stp_map_print (mapiis, "%3s\t\t%1d %2d -> %s"); - - _stp_printf("\nsorting from high to low on key 3\n"); - _stp_map_sort (mapiis, 3, 1); - _stp_map_print (mapiis, "%3s\t\t%1d %2d -> %s"); - - _stp_printf("\ntop 3 alphabetical by value\n"); - _stp_map_sortn (mapiis, 3, 0, -1); - _stp_map_printn (mapiis, 3, "%s -> %1d %2d %3s"); - - _stp_printf("\nbottom 2 alphabetical by value\n"); - _stp_map_sortn (mapiis, 2, 0, 1); - _stp_map_printn (mapiis, 2, "%s -> %1d %2d %3s"); - - - _stp_printf("\ntop 5 sorted by key 1\n"); - _stp_map_sortn (mapiis, 5, 1, 1); - _stp_map_printn (mapiis, 5, "%1d %2d %3s -> %s"); - _stp_printf("\nbottom 5 sorted by key 1\n"); - _stp_map_sortn (mapiis, 5, 1, -1); - _stp_map_printn (mapiis, 5, "%1d %2d %3s -> %s"); - - MAP mapss = _stp_map_new_ssi(4); - _stp_map_set_ssi (mapss, "Riga", "Latvia", 135786); - _stp_map_set_ssi (mapss, "Sofia", "Bulgaria", 138740); - _stp_map_set_ssi (mapss, "Valletta", "Malta", 1); - _stp_map_set_ssi (mapss, "Nicosia", "Cyprus", -1); - - _stp_printf("sorted by population from low to high\n"); - _stp_map_sort (mapss, 0, -1); - _stp_map_print (mapss, "%1s is the capitol of %2s and the nerd population is %d"); - _stp_printf("sorted by population from high to low\n"); - _stp_map_sort (mapss, 0, 1); - _stp_map_print (mapss, "%1s is the capitol of %2s and the nerd population is %d"); - - _stp_map_del(mapss); - _stp_map_del(mapiis); - - return 0; -} diff --git a/runtime/tests/maps/sort2.c b/runtime/tests/maps/sort2.c deleted file mode 100644 index 0b3bc547..00000000 --- a/runtime/tests/maps/sort2.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "runtime.h" - -/* test of map sorting. Just like sort.c, except test with an odd number of nodes */ -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE STRING -#include "map-gen.c" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP mapiis = _stp_map_new_iiss(10); - - /* try to crash the sorts with sorting an empty list */ - _stp_map_sort (mapiis, 0, -1); - _stp_map_sort (mapiis, 0, 1); - _stp_map_sortn (mapiis, 3, 0, -1); - _stp_map_sortn (mapiis, 0, 0, -1); - - /* load some test data */ - _stp_map_add_iiss (mapiis, 3,4,"California","Sacramento" ); - _stp_map_set_iiss (mapiis, 5,6,"Washington","Olympia" ); - _stp_map_set_iiss (mapiis, 7,8,"Oregon","Salem" ); - _stp_map_set_iiss (mapiis, 7,8,"Nevada","Carson City" ); - _stp_map_set_iiss (mapiis, 1, 4,"New Mexico","Santa Fe" ); - _stp_map_set_iiss (mapiis, -1,9,"North Carolina","Raleigh" ); - _stp_map_set_iiss (mapiis, 5,5,"Massachusetts","Boston" ); - _stp_map_set_iiss (mapiis, 8,8,"Iowa","Des Moines" ); - _stp_map_set_iiss (mapiis, 1,2,"Ohio","Columbus" ); - - _stp_printf("sorting from A-Z on value\n"); - _stp_map_sort (mapiis, 0, -1); - _stp_map_print (mapiis, "%s -> %1d %2d %3s"); - - _stp_printf("\nsorting from Z-A on value\n"); - _stp_map_sort (mapiis, 0, 1); - _stp_map_print (mapiis, "%s -> %1d %2d %3s"); - - _stp_printf("\nsorting from low to high on key 1\n"); - _stp_map_sort (mapiis, 1, -1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from high to low on key 1\n"); - _stp_map_sort (mapiis, 1, 1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from low to high on key 2\n"); - _stp_map_sort (mapiis, 2, -1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - _stp_printf("\nsorting from high to low on key 2\n"); - _stp_map_sort (mapiis, 2, 1); - _stp_map_print (mapiis, "%1d %2d %3s -> %s"); - - - _stp_printf("\nsorting from low to high on key 3\n"); - _stp_map_sort (mapiis, 3, -1); - _stp_map_print (mapiis, "%3s\t\t%1d %2d -> %s"); - - _stp_printf("\nsorting from high to low on key 3\n"); - _stp_map_sort (mapiis, 3, 1); - _stp_map_print (mapiis, "%3s\t\t%1d %2d -> %s"); - - _stp_printf("\ntop 3 alphabetical by value\n"); - _stp_map_sortn (mapiis, 3, 0, -1); - _stp_map_printn (mapiis, 3, "%s -> %1d %2d %3s"); - - _stp_printf("\nbottom 2 alphabetical by value\n"); - _stp_map_sortn (mapiis, 2, 0, 1); - _stp_map_printn (mapiis, 2, "%s -> %1d %2d %3s"); - - - _stp_printf("\ntop 5 sorted by key 1\n"); - _stp_map_sortn (mapiis, 5, 1, 1); - _stp_map_printn (mapiis, 5, "%1d %2d %3s -> %s"); - _stp_printf("\nbottom 5 sorted by key 1\n"); - _stp_map_sortn (mapiis, 5, 1, -1); - _stp_map_printn (mapiis, 5, "%1d %2d %3s -> %s"); - - MAP mapss = _stp_map_new_ssi(5); - _stp_map_set_ssi (mapss, "Riga", "Latvia", 135786); - _stp_map_set_ssi (mapss, "Sofia", "Bulgaria", 138740); - _stp_map_set_ssi (mapss, "Valletta", "Malta", 1); - _stp_map_set_ssi (mapss, "Nicosia", "Cyprus", -1); - _stp_map_set_ssi (mapss, "Chisinau", "Moldova", 1024); - - _stp_printf("sorted by population from low to high\n"); - _stp_map_sort (mapss, 0, -1); - _stp_map_print (mapss, "%1s is the capitol of %2s and the nerd population is %d"); - _stp_printf("sorted by population from high to low\n"); - _stp_map_sort (mapss, 0, 1); - _stp_map_print (mapss, "%1s is the capitol of %2s and the nerd population is %d"); - - _stp_map_del(mapss); - _stp_map_del(mapiis); - - return 0; -} diff --git a/runtime/tests/maps/sort_stat.c b/runtime/tests/maps/sort_stat.c deleted file mode 100644 index f3f0435e..00000000 --- a/runtime/tests/maps/sort_stat.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "runtime.h" - -/* test of map sorting */ - -#define VALUE_TYPE STAT -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP mapssx = _stp_map_new_ssx (8, HIST_LINEAR, 0, 100, 10 ); - int i,j; - - for (i = 0; i < 100; i++) - for (j = 0; j <= i*10 ; j++ ) - _stp_map_add_ssx (mapssx, "California", "Sacramento", i); - - for (i = 0; i < 10; i++) - for (j = 0; j < 10 ; j++ ) - _stp_map_add_ssx (mapssx, "Washington", "Olympia", j * i ); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/5 ; j++ ) - _stp_map_add_ssx (mapssx, "Oregon", "Salem", i); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/10 ; j++ ) - _stp_map_add_ssx (mapssx, "Nevada", "Carson City", i + j); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/20 ; j++ ) - _stp_map_add_ssx (mapssx, "Ohio", "Columbus", 50); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/10 ; j++ ) - _stp_map_add_ssx (mapssx, "North Carolina", "Raleigh", 100 - j * i); - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i ; j++ ) - _stp_map_add_ssx (mapssx, "New Mexico", "Santa Fe", 50 - j); - - - _stp_map_print (mapssx, "Bogons per packet for %1s\ncount:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_printf("SORTED BY COUNT\n"); - _stp_map_sort (mapssx, SORT_COUNT, 1); - _stp_map_print (mapssx, "%C %1s"); - - _stp_printf("SORTED BY COUNT (low to high)\n"); - _stp_map_sort (mapssx, SORT_COUNT, -1); - _stp_map_print (mapssx, "%C %1s"); - - _stp_printf("SORTED BY SUM\n"); - _stp_map_sort (mapssx, SORT_SUM, 1); - _stp_map_print (mapssx, "%S %1s"); - - _stp_printf("SORTED BY SUM (low to high)\n"); - _stp_map_sort (mapssx, SORT_SUM, -1); - _stp_map_print (mapssx, "%S %1s"); - - _stp_printf("SORTED BY MIN\n"); - _stp_map_sort (mapssx, SORT_MIN, 1); - _stp_map_print (mapssx, "%m %1s"); - - _stp_printf("SORTED BY MIN (low to high)\n"); - _stp_map_sort (mapssx, SORT_MIN, -1); - _stp_map_print (mapssx, "%m %1s"); - - _stp_printf("SORTED BY MAX\n"); - _stp_map_sort (mapssx, SORT_MAX, 1); - _stp_map_print (mapssx, "%M %1s"); - - _stp_printf("SORTED BY MAX (low to high)\n"); - _stp_map_sort (mapssx, SORT_MAX, -1); - _stp_map_print (mapssx, "%M %1s"); - - _stp_printf("SORTED BY AVG\n"); - _stp_map_sort (mapssx, SORT_AVG, 1); - _stp_map_print (mapssx, "%A %1s"); - - _stp_printf("SORTED BY AVG (low to high)\n"); - _stp_map_sort (mapssx, SORT_AVG, -1); - _stp_map_print (mapssx, "%A %1s"); - - _stp_map_del (mapssx); - return 0; -} diff --git a/runtime/tests/maps/ssssss.c b/runtime/tests/maps/ssssss.c deleted file mode 100644 index 1cc020b7..00000000 --- a/runtime/tests/maps/ssssss.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "runtime.h" - -/* test of maps with keys 5 strings and values of string */ -#define VALUE_TYPE STRING -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#define KEY3_TYPE STRING -#define KEY4_TYPE STRING -#define KEY5_TYPE STRING -#include "map-gen.c" - -#include "map.c" - -int main () -{ - struct map_node *ptr; - MAP map = _stp_map_new_ssssss(4); - - _stp_map_set_ssssss (map, "1ABC", "2ABC", "3ABC", "4ABC", "5ABC", "666"); - _stp_map_set_ssssss (map, "1QRS", "2QRS", "3QRS", "4QRS", "5QRS", "777"); - _stp_map_set_ssssss (map, "1abc", "2abc", "3abc", "4abc", "5abc", "888"); - _stp_map_set_ssssss (map, "1XYZ", "2XYZ", "3XYZ", "4XYZ", "5XYZ", "999"); - - foreach (map, ptr) - printf ("map[%s, %s, %s, %s, %s] = %s\n", - _stp_key_get_str(ptr,1), - _stp_key_get_str(ptr,2), - _stp_key_get_str(ptr,3), - _stp_key_get_str(ptr,4), - _stp_key_get_str(ptr,5), - _stp_get_str(ptr)); - - - _stp_map_print(map,"%1s and %2s and %3s and %4s and %5s ---> %s"); - _stp_map_del (map); - return 0; -} diff --git a/runtime/tests/math/Makefile b/runtime/tests/math/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/math/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/math/all.tcl b/runtime/tests/math/all.tcl deleted file mode 100644 index 23757202..00000000 --- a/runtime/tests/math/all.tcl +++ /dev/null @@ -1,4 +0,0 @@ -package require tcltest -namespace import -force tcltest::* -tcltest::testsDirectory [file dir [info script]] -tcltest::runAllTests diff --git a/runtime/tests/math/div64.c b/runtime/tests/math/div64.c deleted file mode 100644 index ed033d5b..00000000 --- a/runtime/tests/math/div64.c +++ /dev/null @@ -1,182 +0,0 @@ -/* test of 64-bit division */ -#include "runtime.h" -#define LLONG_MAX 0x7fffffffffffffffLL -#ifndef LLONG_MIN -#define LLONG_MIN 0x8000000000000000LL -#endif - -/* This tests a lot of edge conditions.*/ -/* Then it does 10 million random divisions, comparing the result */ -/* with the results from glibc */ - -int main() -{ - int64_t x, y, div1, mod1, div2, mod2; - const char *error; - int i; - - x = 0; - y = 0; - div1 = _stp_div64(&error, x, y); - if (div1 != 0 || *error != 'd') { - printf("Failed 0/0 test\n"); - exit(-1); - } - error = ""; - - mod1 = _stp_mod64(&error, x, y); - if (mod1 != 0 || *error != 'd') { - printf("Failed 0%0 test\n"); - exit(-1); - } - error = ""; - - x = 1; - y = 0; - div1 = _stp_div64(&error, x, y); - if (div1 != 0 || *error != 'd') { - printf("Failed 1/0 test\n"); - exit(-1); - } - error = ""; - - mod1 = _stp_mod64(&error, x, y); - if (mod1 != 0 || *error != 'd') { - printf("Failed 1%0 test\n"); - exit(-1); - } - error = ""; - - x = 0; - y = 1; - - div1 = _stp_div64(&error, x, y); - if (*error || div1 != 0) { - printf("Failed 0/1 test\n"); - exit(-1); - } - - mod1 = _stp_mod64(&error, x, y); - if (*error || mod1 != 0) { - printf("Failed 0%1 test\n"); - exit(-1); - } - - x = -1; - y = -1; - - div1 = _stp_div64(&error, x, y); - if (*error || div1 != 1) { - printf("Failed -1/-1 test\n"); - exit(-1); - } - - mod1 = _stp_mod64(&error, x, y); - if (*error || mod1 != 0) { - printf("Failed -1%-1 test\n"); - exit(-1); - } - - - for (y = -1; y < 2; y++) { - if (y == 0) - continue; - -#ifndef __LP64__ - for (x = LONG_MIN - 1LL; x < LONG_MIN + 2LL; x++ ) { - div1 = _stp_div64(&error, x, y); - mod1 = _stp_mod64(&error, x, y); - div2 = x/y; - mod2 = x%y; - if (div1 != div2) { - printf ("%lld/%lld (%llx/%llx) was %lld and should have been %lld\n", x,y,x,y,div1,div2); - exit (-1); - } - if (mod1 != mod2) { - printf ("%lld\%%%lld (%llx/%llx) was %lld and should have been %lld\n", x,y,x,y,mod1,mod2); - exit (-1); - } - } - - for (x = LONG_MAX - 1LL; x < LONG_MAX + 2LL; x++ ) { - div1 = _stp_div64(&error, x, y); - mod1 = _stp_mod64(&error, x, y); - div2 = x/y; - mod2 = x%y; - if (div1 != div2) { - printf ("%lld/%lld (%llx/%llx) was %lld and should have been %lld\n", x,y,x,y,div1,div2); - exit (-1); - } - if (mod1 != mod2) { - printf ("%lld\%%%lld (%llx/%llx) was %lld and should have been %lld\n", x,y,x,y,mod1,mod2); - exit (-1); - } - } -#endif - - for (x = LLONG_MIN; x <= LLONG_MIN + 1LL; x++ ) { - div1 = _stp_div64(&error, x, y); - mod1 = _stp_mod64(&error, x, y); -#ifdef __LP64__ - if (x == LLONG_MIN && y == -1) { - if (div1 != LLONG_MIN) { - printf ("%lld/%lld was %lld and should have been %lld (overflow)\n", x,y,div1,LLONG_MIN); - exit(-1); - } - continue; - } -#endif - div2 = x/y; - mod2 = x%y; - if (div1 != div2) { - printf ("%lld/%lld was %lld and should have been %lld\n", x,y,div1,div2); - exit (-1); - } - if (mod1 != mod2) { - printf ("%lld\%%%lld was %lld and should have been %lld\n", x,y,mod1,mod2); - exit (-1); - } - } - - for (x = LONG_MAX - 1; x > 0 && x <= LONG_MAX; x++ ) { - div1 = _stp_div64(&error, x, y); - mod1 = _stp_mod64(&error, x, y); - div2 = x/y; - mod2 = x%y; - if (div1 != div2) { - printf ("%lld/%lld was %lld and should have been %lld\n", x,y,div1,div2); - exit (-1); - } - if (mod1 != mod2) { - printf ("%lld\%%%lld was %lld and should have been %lld\n", x,y,mod1,mod2); - exit (-1); - } - } - } - - /* just for fun, do ten million random divisions and mods */ - for (i = 0; i < 10000000; i++) { - x = mrand48(); - y = mrand48(); - if (y == 0) { - i--; - continue; - } - - div1 = _stp_div64(NULL, x, y); - mod1 = _stp_mod64(NULL, x, y); - div2 = x/y; - mod2 = x%y; - - if (div1 != div2) { - printf ("%lld/%lld was %lld and should have been %lld\n", x,y,div1,div2); - exit (-1); - } - if (mod1 != mod2) { - printf ("%lld\%%%lld was %lld and should have been %lld\n", x,y,mod1,mod2); - exit (-1); - } - } - printf("OK\n"); - return 0; -} diff --git a/runtime/tests/math/math.test b/runtime/tests/math/math.test deleted file mode 100644 index e7c58ba0..00000000 --- a/runtime/tests/math/math.test +++ /dev/null @@ -1,19 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -cd $tcltest::testsDirectory - -set CFLAGS "-Os" -set KPATH "/lib/modules/[exec uname -r]/build/include" -set MPATH "/lib/modules/[exec uname -r]/build/include/asm/mach-default" -set PATH "../../user" - -test printf_A {Basic printf test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test div64.c -} -body { - exec ./test -} -result {OK} - -exec rm test - -cleanupTests diff --git a/runtime/tests/pmaps/Makefile b/runtime/tests/pmaps/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/pmaps/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/pmaps/all.tcl b/runtime/tests/pmaps/all.tcl deleted file mode 100644 index c0b38a0e..00000000 --- a/runtime/tests/pmaps/all.tcl +++ /dev/null @@ -1,5 +0,0 @@ -package require tcltest -namespace import -force tcltest::* -tcltest::testsDirectory [file dir [info script]] -tcltest::runAllTests - diff --git a/runtime/tests/pmaps/ii.c b/runtime/tests/pmaps/ii.c deleted file mode 100644 index dfce0a07..00000000 --- a/runtime/tests/pmaps/ii.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of int64 and value of int64 */ - -/* It's not clear this would ever be used in the systemtap language. - It would be useful as an array of counters. */ - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ii(4); - int64_t x; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ii(map, 1, _processor_number); - _stp_pmap_add_ii(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ii(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ii(map, 4, 1); - } - - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_ii (map, 3); - if (x != _processor_number * _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(_processor_number * _processor_number)); - x = _stp_pmap_get_cpu_ii (map, 1); - if (x != _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)_processor_number); - x = _stp_pmap_get_cpu_ii (map, 2); - if (x != 10 * _processor_number + 1) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(10 * _processor_number + 1)); - x = _stp_pmap_get_cpu_ii (map, 4); - if (x != 1LL) - printf("ERROR: Got %lld when expected %lld\n", x, 1LL); - } - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map,0, "map[%1d] = %d", _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = %d"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/ii2.c b/runtime/tests/pmaps/ii2.c deleted file mode 100644 index 0a28ad87..00000000 --- a/runtime/tests/pmaps/ii2.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "runtime.h" - -/* test of maps and pmaps with keys of int64 and value of int64 */ - -/* Make sure we can cleanly generate both */ - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "map-gen.c" - -#include "map.c" - -int main () -{ - MAP map = _stp_map_new_ii(4); - PMAP pmap = _stp_pmap_new_ii(4); - int64_t x; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ii(pmap, 1, _processor_number); - _stp_pmap_add_ii(pmap, 2, 10 *_processor_number + 1); - _stp_pmap_add_ii(pmap, 3, _processor_number * _processor_number); - _stp_pmap_add_ii(pmap, 4, 1); - _stp_map_add_ii(map, 1, _processor_number); - _stp_map_add_ii(map, 2, 10 *_processor_number + 1); - _stp_map_add_ii(map, 3, _processor_number * _processor_number); - _stp_map_add_ii(map, 4, 1); - } - - _processor_number = 0; - - /* print the aggregated data */ - _stp_map_print(map,"map[%1d] = %d"); - _stp_pmap_print(pmap,"pmap[%1d] = %d"); - - _stp_map_del (map); - _stp_pmap_del (pmap); - return 0; -} - diff --git a/runtime/tests/pmaps/ii3.c b/runtime/tests/pmaps/ii3.c deleted file mode 100644 index e2dee7a6..00000000 --- a/runtime/tests/pmaps/ii3.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of int64 and value of int64 */ - -/* It's not clear this would ever be used in the systemtap language. - It would be useful as an array of counters. */ - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ii(4); - int i; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ii(map, 1, _processor_number); - _stp_pmap_add_ii(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ii(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ii(map, 4, 1); - } - - _processor_number = 0; - - /* get the data with get calls. this is not very efficient */ - for (i = 1; i < 5; i++) - printf("map[%d] = %lld\n", i, _stp_pmap_get_ii(map, i)); - printf("\n"); - - /* do it again. test that the aggregation map got cleared */ - for (i = 1; i < 5; i++) - printf("map[%d] = %lld\n", i, _stp_pmap_get_ii(map, i)); - printf("\n"); - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = %d"); - - /* delete an entry and repeat */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) - _stp_pmap_set_ii(map, 2, 0); - _processor_number = 0; - - for (i = 1; i < 5; i++) - printf("map[%d] = %lld\n", i, _stp_pmap_get_ii(map, i)); - printf("\n"); - - _stp_pmap_print(map,"map[%1d] = %d"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/is.c b/runtime/tests/pmaps/is.c deleted file mode 100644 index a97d8b0b..00000000 --- a/runtime/tests/pmaps/is.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of int64 and value of string */ - -/* It's not clear this would ever be used in the systemtap language. - It is not clear this would be useful. */ - -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_is(4); - char *x; - char buf[32]; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - sprintf(buf, "%d,", _processor_number); - _stp_pmap_add_is(map, 1, buf); - sprintf(buf, "%d,", 10 *_processor_number + 1); - _stp_pmap_add_is(map, 2, buf); - sprintf(buf, "%d,", _processor_number * _processor_number); - _stp_pmap_add_is(map, 3, buf); - _stp_pmap_add_is(map, 4, "1,"); - } - - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_is (map, 3); - sprintf(buf, "%d,", _processor_number * _processor_number); - if (strcmp(x, buf)) - printf("ERROR: Got %s when expected %s\n", x, buf); - x = _stp_pmap_get_cpu_is (map, 1); - sprintf(buf, "%d,", _processor_number); - if (strcmp(x, buf)) - printf("ERROR: Got %s when expected %s\n", x, buf); - x = _stp_pmap_get_cpu_is (map, 4); - sprintf(buf, "%d,", 1); - if (strcmp(x, buf)) - printf("ERROR: Got %s when expected %s\n", x, buf); - x = _stp_pmap_get_cpu_is (map, 2); - sprintf(buf, "%d,", 10 * _processor_number +1); - if (strcmp(x, buf)) - printf("ERROR: Got %s when expected %s\n", x, buf); - } - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map,0, "map[%1d] = %s", _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = %s"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/ix.c b/runtime/tests/pmaps/ix.c deleted file mode 100644 index 0eba2d54..00000000 --- a/runtime/tests/pmaps/ix.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of int64 and value of stat */ - -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ix(4, HIST_LINEAR, 0, 100, 10); - int64_t x; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ix(map, 1, _processor_number); - _stp_pmap_add_ix(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ix(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ix(map, 4, 1); - } - -#if 0 - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_ix (map, 3); - if (x != _processor_number * _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(_processor_number * _processor_number)); - x = _stp_pmap_get_cpu_ix (map, 1); - if (x != _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)_processor_number); - x = _stp_pmap_get_cpu_ix (map, 2); - if (x != 10 * _processor_number + 1) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(10 * _processor_number + 1)); - x = _stp_pmap_get_cpu_ix (map, 4); - if (x != 1LL) - printf("ERROR: Got %lld when expected %lld\n", x, 1LL); - } -#endif - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map, - 0, - "map[%1d] = count:%C sum:%S avg:%A min:%m max:%M", - _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/ix2.c b/runtime/tests/pmaps/ix2.c deleted file mode 100644 index 638e5226..00000000 --- a/runtime/tests/pmaps/ix2.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of int64 and value of stat */ - -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ix(4, HIST_LINEAR, 0, 100, 10); - int i; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ix(map, 1, _processor_number); - _stp_pmap_add_ix(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ix(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ix(map, 4, 1); - } - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map, - 0, - "map[%1d] = count:%C sum:%S avg:%A min:%m max:%M", - _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - /* now use GET */ - for (i = 1; i < 5; i++) - printf("map[%d] Sum = %lld\n", i, _stp_pmap_get_ix(map, i)->sum); - printf("\n"); - - /* delete an entry and repeat */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) - _stp_pmap_set_ix(map, 2, 0); - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - /* now use GET */ - for (i = 1; i < 5; i++) { - stat *sd = _stp_pmap_get_ix(map, i); - if (sd) - printf("map[%d] Sum = %lld\n", i, sd->sum); - } - printf("\n"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/ix_log.c b/runtime/tests/pmaps/ix_log.c deleted file mode 100644 index 4f3c5503..00000000 --- a/runtime/tests/pmaps/ix_log.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "runtime.h" - -/* like ix.c, except use HIST_LOG */ -/* test of pmaps with keys of int64 and value of stat */ - -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ix(4, HIST_LOG, 5); - int64_t x; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ix(map, 1, _processor_number); - _stp_pmap_add_ix(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ix(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ix(map, 4, 1); - } - -#if 0 - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_ix (map, 3); - if (x != _processor_number * _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(_processor_number * _processor_number)); - x = _stp_pmap_get_cpu_ix (map, 1); - if (x != _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)_processor_number); - x = _stp_pmap_get_cpu_ix (map, 2); - if (x != 10 * _processor_number + 1) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(10 * _processor_number + 1)); - x = _stp_pmap_get_cpu_ix (map, 4); - if (x != 1LL) - printf("ERROR: Got %lld when expected %lld\n", x, 1LL); - } -#endif - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map, - 0, - "map[%1d] = count:%C sum:%S avg:%A min:%m max:%M", - _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/ix_none.c b/runtime/tests/pmaps/ix_none.c deleted file mode 100644 index 440b0069..00000000 --- a/runtime/tests/pmaps/ix_none.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "runtime.h" - -/* like ix.c, except with no histogram */ -/* test of pmaps with keys of int64 and value of stat */ - -#define VALUE_TYPE STAT -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_ix(4, HIST_NONE); - int64_t x; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ix(map, 1, _processor_number); - _stp_pmap_add_ix(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ix(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ix(map, 4, 1); - } - -#if 0 - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_ix (map, 3); - if (x != _processor_number * _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(_processor_number * _processor_number)); - x = _stp_pmap_get_cpu_ix (map, 1); - if (x != _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)_processor_number); - x = _stp_pmap_get_cpu_ix (map, 2); - if (x != 10 * _processor_number + 1) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(10 * _processor_number + 1)); - x = _stp_pmap_get_cpu_ix (map, 4); - if (x != 1LL) - printf("ERROR: Got %lld when expected %lld\n", x, 1LL); - } -#endif - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map, - 0, - "map[%1d] = count:%C sum:%S avg:%A min:%m max:%M", - _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1d] = count:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/map_format.c b/runtime/tests/pmaps/map_format.c deleted file mode 100644 index b27506e0..00000000 --- a/runtime/tests/pmaps/map_format.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "runtime.h" - -/* map formatting test. Same as the non-pmap version. Output should be identical */ - -/* torture test of map formatting */ -#define VALUE_TYPE STRING -#define KEY1_TYPE INT64 -#define KEY2_TYPE INT64 -#define KEY3_TYPE STRING -#include "pmap-gen.c" - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "pmap-gen.c" - -#define VALUE_TYPE STAT -#define KEY1_TYPE STRING -#define KEY2_TYPE STRING -#include "pmap-gen.c" - -#include "map.c" - -void inc_cpu(void) -{ - _processor_number++; - if (_processor_number == NR_CPUS) - _processor_number = 0; -} - -int main () -{ - PMAP mapiis = _stp_pmap_new_iiss(4); - _processor_number = 0; - _stp_pmap_set_iiss (mapiis, 1,2,"Ohio", "Columbus" ); - _stp_pmap_set_iiss (mapiis, 3,4,"California", "Sacramento" ); - _stp_pmap_set_iiss (mapiis, 5,6,"Washington", "Olympia" ); - _stp_pmap_set_iiss (mapiis, 7,8,"Oregon", "Salem" ); - _stp_pmap_print (mapiis, "%s -> mapiis %1d %2d %3s"); - - /* test printing of '%' */ - _stp_pmap_print (mapiis, "%s %% %3s"); - - /* very bad string. don't crash */ - _stp_pmap_print (mapiis, "%s -> mapiis %1s %2s %3d %4d"); - - PMAP mapss = _stp_pmap_new_ssi(4); - _stp_pmap_set_ssi (mapss, "Riga", "Latvia", 0x0000c0dedbad0000LL); - _stp_pmap_set_ssi (mapss, "Sofia", "Bulgaria", 0xdeadf00d12345678LL); - _stp_pmap_set_ssi (mapss, "Valletta", "Malta", 1); - _stp_pmap_set_ssi (mapss, "Nicosia", "Cyprus", -1); - _stp_pmap_print (mapss, "The capitol of %1s is %2s and the nerd population is %d"); - _stp_pmap_print (mapss, "The capitol of %1s is %2s and the nerd population is %x"); - _stp_pmap_print (mapss, "The capitol of %1s is %2s and the nerd population is %X"); - - PMAP mapssx = _stp_pmap_new_ssx (4, HIST_LINEAR, 0, 100, 10 ); - int i,j; - - for (i = 0; i < 100; i++) - for (j = 0; j <= i*10 ; j++ ) { - inc_cpu(); - _stp_pmap_add_ssx (mapssx, "Riga", "Latvia", i); - } - - for (i = 0; i < 10; i++) - for (j = 0; j < 10 ; j++ ) { - inc_cpu(); - _stp_pmap_add_ssx (mapssx, "Sofia", "Bulgaria", j * i ); - } - - for (i = 0; i < 100; i += 10) - for (j = 0; j < i/10 ; j++ ) { - inc_cpu(); - _stp_pmap_add_ssx (mapssx, "Valletta", "Malta", i); - } - - _stp_pmap_print (mapssx, "Bogons per packet for %1s\ncount:%C sum:%S avg:%A min:%m max:%M\n%H"); - - _stp_pmap_print (mapssx, "%C was the count for %1s, %2s"); - - /* here's how to print a map without using _stp_pmap_print(). */ - _stp_pmap_agg (mapssx); - struct map_node *ptr; - foreach (_stp_pmap_get_agg(mapssx), ptr) - _stp_printf ("mapssx[%09s,%09s] = %llX\n", key1str(ptr), key2str(ptr), _stp_get_stat(ptr)->sum); - _stp_print_flush(); - - _stp_pmap_del (mapssx); - _stp_pmap_del (mapiis); - _stp_pmap_del (mapss); - return 0; -} diff --git a/runtime/tests/pmaps/pmap.test b/runtime/tests/pmaps/pmap.test deleted file mode 100644 index fb5c3d0d..00000000 --- a/runtime/tests/pmaps/pmap.test +++ /dev/null @@ -1,678 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -cd $tcltest::testsDirectory - -set CFLAGS "-Os" -set KPATH "/lib/modules/[exec uname -r]/build/include" -set MPATH "/lib/modules/[exec uname -r]/build/include/asm/mach-default" -set PATH "../../user" - -test ii {Test of int64 keys and int64 values} -setup { - puts "gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ii.c" - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ii.c -} -body { - exec ./test -} -result {CPU #0 -map[2] = 1 -map[4] = 1 - -CPU #1 -map[1] = 1 -map[2] = 11 -map[3] = 1 -map[4] = 1 - -CPU #2 -map[1] = 2 -map[2] = 21 -map[3] = 4 -map[4] = 1 - -CPU #3 -map[1] = 3 -map[2] = 31 -map[3] = 9 -map[4] = 1 - -CPU #4 -map[1] = 4 -map[2] = 41 -map[3] = 16 -map[4] = 1 - -CPU #5 -map[1] = 5 -map[2] = 51 -map[3] = 25 -map[4] = 1 - -CPU #6 -map[1] = 6 -map[2] = 61 -map[3] = 36 -map[4] = 1 - -CPU #7 -map[1] = 7 -map[2] = 71 -map[3] = 49 -map[4] = 1 - -map[2] = 288 -map[4] = 8 -map[1] = 28 -map[3] = 140 -} - -test is {Test of int64 keys and string values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test is.c -} -body { - exec ./test -} -result {CPU #0 -map[1] = 0, -map[2] = 1, -map[3] = 0, -map[4] = 1, - -CPU #1 -map[1] = 1, -map[2] = 11, -map[3] = 1, -map[4] = 1, - -CPU #2 -map[1] = 2, -map[2] = 21, -map[3] = 4, -map[4] = 1, - -CPU #3 -map[1] = 3, -map[2] = 31, -map[3] = 9, -map[4] = 1, - -CPU #4 -map[1] = 4, -map[2] = 41, -map[3] = 16, -map[4] = 1, - -CPU #5 -map[1] = 5, -map[2] = 51, -map[3] = 25, -map[4] = 1, - -CPU #6 -map[1] = 6, -map[2] = 61, -map[3] = 36, -map[4] = 1, - -CPU #7 -map[1] = 7, -map[2] = 71, -map[3] = 49, -map[4] = 1, - -map[2] = 1,11,21,31,41,51,61,71, -map[4] = 1,1,1,1,1,1,1,1, -map[1] = 0,1,2,3,4,5,6,7, -map[3] = 0,1,4,9,16,25,36,49, -} - -test si {Test of string keys and int64 values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test si.c -} -body { - exec ./test -} -result {CPU #0 -map[TWO] = 1 -map[FOUR] = 1 - -CPU #1 -map[ONE] = 1 -map[TWO] = 11 -map[THREE] = 1 -map[FOUR] = 1 - -CPU #2 -map[ONE] = 2 -map[TWO] = 21 -map[THREE] = 4 -map[FOUR] = 1 - -CPU #3 -map[ONE] = 3 -map[TWO] = 31 -map[THREE] = 9 -map[FOUR] = 1 - -CPU #4 -map[ONE] = 4 -map[TWO] = 41 -map[THREE] = 16 -map[FOUR] = 1 - -CPU #5 -map[ONE] = 5 -map[TWO] = 51 -map[THREE] = 25 -map[FOUR] = 1 - -CPU #6 -map[ONE] = 6 -map[TWO] = 61 -map[THREE] = 36 -map[FOUR] = 1 - -CPU #7 -map[ONE] = 7 -map[TWO] = 71 -map[THREE] = 49 -map[FOUR] = 1 - -map[FOUR] = 8 -map[TWO] = 288 -map[THREE] = 140 -map[ONE] = 28 -} - -test ix {Test of int64 keys and stat values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ix.c -} -body { - exec ./test -} -result {CPU #0 -map[1] = count:1 sum:0 avg:0 min:0 max:0 -map[2] = count:1 sum:1 avg:1 min:1 max:1 -map[3] = count:1 sum:0 avg:0 min:0 max:0 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #1 -map[1] = count:1 sum:1 avg:1 min:1 max:1 -map[2] = count:1 sum:11 avg:11 min:11 max:11 -map[3] = count:1 sum:1 avg:1 min:1 max:1 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #2 -map[1] = count:1 sum:2 avg:2 min:2 max:2 -map[2] = count:1 sum:21 avg:21 min:21 max:21 -map[3] = count:1 sum:4 avg:4 min:4 max:4 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #3 -map[1] = count:1 sum:3 avg:3 min:3 max:3 -map[2] = count:1 sum:31 avg:31 min:31 max:31 -map[3] = count:1 sum:9 avg:9 min:9 max:9 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #4 -map[1] = count:1 sum:4 avg:4 min:4 max:4 -map[2] = count:1 sum:41 avg:41 min:41 max:41 -map[3] = count:1 sum:16 avg:16 min:16 max:16 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #5 -map[1] = count:1 sum:5 avg:5 min:5 max:5 -map[2] = count:1 sum:51 avg:51 min:51 max:51 -map[3] = count:1 sum:25 avg:25 min:25 max:25 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #6 -map[1] = count:1 sum:6 avg:6 min:6 max:6 -map[2] = count:1 sum:61 avg:61 min:61 max:61 -map[3] = count:1 sum:36 avg:36 min:36 max:36 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #7 -map[1] = count:1 sum:7 avg:7 min:7 max:7 -map[2] = count:1 sum:71 avg:71 min:71 max:71 -map[3] = count:1 sum:49 avg:49 min:49 max:49 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -map[2] = count:8 sum:288 avg:36 min:1 max:71 -value |-------------------------------------------------- count - 0 |@ 1 - 10 |@ 1 - 20 |@ 1 - 30 |@ 1 - 40 |@ 1 - 50 |@ 1 - 60 |@ 1 - 70 |@ 1 - 80 | 0 - 90 | 0 - -map[4] = count:8 sum:8 avg:1 min:1 max:1 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[1] = count:8 sum:28 avg:3 min:0 max:7 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[3] = count:8 sum:140 avg:17 min:0 max:49 -value |-------------------------------------------------- count - 0 |@@@@ 4 - 10 |@ 1 - 20 |@ 1 - 30 |@ 1 - 40 |@ 1 - 50 | 0 - 60 | 0 - -} - -test ix_log {Test of int64 keys and stat values (log histogram)} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ix_log.c -} -body { - exec ./test -} -result {CPU #0 -map[1] = count:1 sum:0 avg:0 min:0 max:0 -map[2] = count:1 sum:1 avg:1 min:1 max:1 -map[3] = count:1 sum:0 avg:0 min:0 max:0 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #1 -map[1] = count:1 sum:1 avg:1 min:1 max:1 -map[2] = count:1 sum:11 avg:11 min:11 max:11 -map[3] = count:1 sum:1 avg:1 min:1 max:1 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #2 -map[1] = count:1 sum:2 avg:2 min:2 max:2 -map[2] = count:1 sum:21 avg:21 min:21 max:21 -map[3] = count:1 sum:4 avg:4 min:4 max:4 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #3 -map[1] = count:1 sum:3 avg:3 min:3 max:3 -map[2] = count:1 sum:31 avg:31 min:31 max:31 -map[3] = count:1 sum:9 avg:9 min:9 max:9 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #4 -map[1] = count:1 sum:4 avg:4 min:4 max:4 -map[2] = count:1 sum:41 avg:41 min:41 max:41 -map[3] = count:1 sum:16 avg:16 min:16 max:16 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #5 -map[1] = count:1 sum:5 avg:5 min:5 max:5 -map[2] = count:1 sum:51 avg:51 min:51 max:51 -map[3] = count:1 sum:25 avg:25 min:25 max:25 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #6 -map[1] = count:1 sum:6 avg:6 min:6 max:6 -map[2] = count:1 sum:61 avg:61 min:61 max:61 -map[3] = count:1 sum:36 avg:36 min:36 max:36 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #7 -map[1] = count:1 sum:7 avg:7 min:7 max:7 -map[2] = count:1 sum:71 avg:71 min:71 max:71 -map[3] = count:1 sum:49 avg:49 min:49 max:49 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -map[2] = count:8 sum:288 avg:36 min:1 max:71 -value |-------------------------------------------------- count - 0 | 0 - 1 |@ 1 - 2 | 0 - 4 | 0 - 8 |@@@@@@@ 7 - -map[4] = count:8 sum:8 avg:1 min:1 max:1 -value |-------------------------------------------------- count - 0 | 0 - 1 |@@@@@@@@ 8 - 2 | 0 - 4 | 0 - -map[1] = count:8 sum:28 avg:3 min:0 max:7 -value |-------------------------------------------------- count - 0 |@ 1 - 1 |@ 1 - 2 |@@ 2 - 4 |@@@@ 4 - 8 | 0 - -map[3] = count:8 sum:140 avg:17 min:0 max:49 -value |-------------------------------------------------- count - 0 |@ 1 - 1 |@ 1 - 2 | 0 - 4 |@ 1 - 8 |@@@@@ 5 - -} - -test ix_none {Test of int64 keys and stat values (no histogram)} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ix_none.c -} -body { - exec ./test -} -result {CPU #0 -map[1] = count:1 sum:0 avg:0 min:0 max:0 -map[2] = count:1 sum:1 avg:1 min:1 max:1 -map[3] = count:1 sum:0 avg:0 min:0 max:0 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #1 -map[1] = count:1 sum:1 avg:1 min:1 max:1 -map[2] = count:1 sum:11 avg:11 min:11 max:11 -map[3] = count:1 sum:1 avg:1 min:1 max:1 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #2 -map[1] = count:1 sum:2 avg:2 min:2 max:2 -map[2] = count:1 sum:21 avg:21 min:21 max:21 -map[3] = count:1 sum:4 avg:4 min:4 max:4 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #3 -map[1] = count:1 sum:3 avg:3 min:3 max:3 -map[2] = count:1 sum:31 avg:31 min:31 max:31 -map[3] = count:1 sum:9 avg:9 min:9 max:9 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #4 -map[1] = count:1 sum:4 avg:4 min:4 max:4 -map[2] = count:1 sum:41 avg:41 min:41 max:41 -map[3] = count:1 sum:16 avg:16 min:16 max:16 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #5 -map[1] = count:1 sum:5 avg:5 min:5 max:5 -map[2] = count:1 sum:51 avg:51 min:51 max:51 -map[3] = count:1 sum:25 avg:25 min:25 max:25 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #6 -map[1] = count:1 sum:6 avg:6 min:6 max:6 -map[2] = count:1 sum:61 avg:61 min:61 max:61 -map[3] = count:1 sum:36 avg:36 min:36 max:36 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #7 -map[1] = count:1 sum:7 avg:7 min:7 max:7 -map[2] = count:1 sum:71 avg:71 min:71 max:71 -map[3] = count:1 sum:49 avg:49 min:49 max:49 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -map[2] = count:8 sum:288 avg:36 min:1 max:71 - -map[4] = count:8 sum:8 avg:1 min:1 max:1 - -map[1] = count:8 sum:28 avg:3 min:0 max:7 - -map[3] = count:8 sum:140 avg:17 min:0 max:49 - -} - -test map_format {Test of map formatting and histograms} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test map_format.c -} -body { - exec ./test -} -result {Columbus -> mapiis 1 2 Ohio -Salem -> mapiis 7 8 Oregon -Olympia -> mapiis 5 6 Washington -Sacramento -> mapiis 3 4 California - -Columbus % Ohio -Salem % Oregon -Olympia % Washington -Sacramento % California - -Columbus -> mapiis -Salem -> mapiis -Olympia -> mapiis -Sacramento -> mapiis - -The capitol of Riga is Latvia and the nerd population is 212063400820736 -The capitol of Sofia is Bulgaria and the nerd population is -2400999087387945352 -The capitol of Nicosia is Cyprus and the nerd population is -1 -The capitol of Valletta is Malta and the nerd population is 1 - -The capitol of Riga is Latvia and the nerd population is c0dedbad0000 -The capitol of Sofia is Bulgaria and the nerd population is deadf00d12345678 -The capitol of Nicosia is Cyprus and the nerd population is ffffffffffffffff -The capitol of Valletta is Malta and the nerd population is 1 - -The capitol of Riga is Latvia and the nerd population is C0DEDBAD0000 -The capitol of Sofia is Bulgaria and the nerd population is DEADF00D12345678 -The capitol of Nicosia is Cyprus and the nerd population is FFFFFFFFFFFFFFFF -The capitol of Valletta is Malta and the nerd population is 1 - -Bogons per packet for Riga -count:49600 sum:3288450 avg:66 min:0 max:99 -value |-------------------------------------------------- count - 0 |@@ 460 - 10 |@@@@@@@ 1460 - 20 |@@@@@@@@@@@@ 2460 - 30 |@@@@@@@@@@@@@@@@@@ 3460 - 40 |@@@@@@@@@@@@@@@@@@@@@@@ 4460 - 50 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 5460 - 60 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6460 - 70 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 7460 - 80 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 8460 - 90 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9460 - -Bogons per packet for Sofia -count:100 sum:2025 avg:20 min:0 max:81 -value |-------------------------------------------------- count - 0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 42 - 10 |@@@@@@@@@@@@@@@@@ 17 - 20 |@@@@@@@@@@@@@ 13 - 30 |@@@@@@@@@ 9 - 40 |@@@@@@@@@ 9 - 50 |@@@@ 4 - 60 |@@@ 3 - 70 |@@ 2 - 80 |@ 1 - 90 | 0 - -Bogons per packet for Valletta -count:45 sum:2850 avg:63 min:10 max:90 -value |-------------------------------------------------- count - 0 | 0 - 10 |@ 1 - 20 |@@ 2 - 30 |@@@ 3 - 40 |@@@@ 4 - 50 |@@@@@ 5 - 60 |@@@@@@ 6 - 70 |@@@@@@@ 7 - 80 |@@@@@@@@ 8 - 90 |@@@@@@@@@ 9 - - -49600 was the count for Riga, Latvia -100 was the count for Sofia, Bulgaria -45 was the count for Valletta, Malta - -mapssx[ Riga, Latvia] = 322D82 -mapssx[ Sofia, Bulgaria] = 7E9 -mapssx[ Valletta, Malta] = B22} - - -test ii2 {Test of maps and pmaps with int64 keys and int64 values} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ii2.c -} -body { - exec ./test -} -result {map[2] = 288 -map[4] = 8 -map[1] = 28 -map[3] = 140 - -pmap[2] = 288 -pmap[4] = 8 -pmap[1] = 28 -pmap[3] = 140 -} - -test ii3 {Test of int64 keys and int64 values with GET} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ii3.c -} -body { - exec ./test -} -result {map[1] = 28 -map[2] = 288 -map[3] = 140 -map[4] = 8 - -map[1] = 28 -map[2] = 288 -map[3] = 140 -map[4] = 8 - -map[2] = 288 -map[4] = 8 -map[1] = 28 -map[3] = 140 - -map[1] = 28 -map[2] = 0 -map[3] = 140 -map[4] = 8 - -map[4] = 8 -map[1] = 28 -map[3] = 140 -} - -test ix2 {Test of int64 keys and sttat values with GET} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test ix2.c -} -body { - exec ./test -} -result {CPU #0 -map[1] = count:1 sum:0 avg:0 min:0 max:0 -map[2] = count:1 sum:1 avg:1 min:1 max:1 -map[3] = count:1 sum:0 avg:0 min:0 max:0 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #1 -map[1] = count:1 sum:1 avg:1 min:1 max:1 -map[2] = count:1 sum:11 avg:11 min:11 max:11 -map[3] = count:1 sum:1 avg:1 min:1 max:1 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #2 -map[1] = count:1 sum:2 avg:2 min:2 max:2 -map[2] = count:1 sum:21 avg:21 min:21 max:21 -map[3] = count:1 sum:4 avg:4 min:4 max:4 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #3 -map[1] = count:1 sum:3 avg:3 min:3 max:3 -map[2] = count:1 sum:31 avg:31 min:31 max:31 -map[3] = count:1 sum:9 avg:9 min:9 max:9 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #4 -map[1] = count:1 sum:4 avg:4 min:4 max:4 -map[2] = count:1 sum:41 avg:41 min:41 max:41 -map[3] = count:1 sum:16 avg:16 min:16 max:16 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #5 -map[1] = count:1 sum:5 avg:5 min:5 max:5 -map[2] = count:1 sum:51 avg:51 min:51 max:51 -map[3] = count:1 sum:25 avg:25 min:25 max:25 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #6 -map[1] = count:1 sum:6 avg:6 min:6 max:6 -map[2] = count:1 sum:61 avg:61 min:61 max:61 -map[3] = count:1 sum:36 avg:36 min:36 max:36 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -CPU #7 -map[1] = count:1 sum:7 avg:7 min:7 max:7 -map[2] = count:1 sum:71 avg:71 min:71 max:71 -map[3] = count:1 sum:49 avg:49 min:49 max:49 -map[4] = count:1 sum:1 avg:1 min:1 max:1 - -map[2] = count:8 sum:288 avg:36 min:1 max:71 -value |-------------------------------------------------- count - 0 |@ 1 - 10 |@ 1 - 20 |@ 1 - 30 |@ 1 - 40 |@ 1 - 50 |@ 1 - 60 |@ 1 - 70 |@ 1 - 80 | 0 - 90 | 0 - -map[4] = count:8 sum:8 avg:1 min:1 max:1 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[1] = count:8 sum:28 avg:3 min:0 max:7 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[3] = count:8 sum:140 avg:17 min:0 max:49 -value |-------------------------------------------------- count - 0 |@@@@ 4 - 10 |@ 1 - 20 |@ 1 - 30 |@ 1 - 40 |@ 1 - 50 | 0 - 60 | 0 - - -map[1] Sum = 28 -map[2] Sum = 288 -map[3] Sum = 140 -map[4] Sum = 8 - -map[4] = count:8 sum:8 avg:1 min:1 max:1 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[1] = count:8 sum:28 avg:3 min:0 max:7 -value |-------------------------------------------------- count - 0 |@@@@@@@@ 8 - 10 | 0 - 20 | 0 - -map[3] = count:8 sum:140 avg:17 min:0 max:49 -value |-------------------------------------------------- count - 0 |@@@@ 4 - 10 |@ 1 - 20 |@ 1 - 30 |@ 1 - 40 |@ 1 - 50 | 0 - 60 | 0 - - -map[1] Sum = 28 -map[3] Sum = 140 -map[4] Sum = 8 -} - - -test size {Test _stp_pmap_size()} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test size.c -} -body { - exec ./test -} -result {} - -catch {exec rm test} - -cleanupTests diff --git a/runtime/tests/pmaps/si.c b/runtime/tests/pmaps/si.c deleted file mode 100644 index 8b05da74..00000000 --- a/runtime/tests/pmaps/si.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "runtime.h" - -/* test of pmaps with keys of string and value of int64 */ - -/* It's not clear this would ever be used in the systemtap language. - It would be useful as an array of counters. */ - -#define VALUE_TYPE INT64 -#define KEY1_TYPE STRING -#include "pmap-gen.c" - -#include "map.c" - -int main () -{ - PMAP map = _stp_pmap_new_si(4); - int64_t x; - - if (!map) - return -1; - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_si(map, "ONE", _processor_number); - _stp_pmap_add_si(map, "TWO", 10 *_processor_number + 1); - _stp_pmap_add_si(map, "THREE", _processor_number * _processor_number); - _stp_pmap_add_si(map, "FOUR", 1); - } - - /* read it back out and verify. Use the special get_cpu call to get non-aggregated data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - x = _stp_pmap_get_cpu_si (map, "THREE"); - if (x != _processor_number * _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(_processor_number * _processor_number)); - x = _stp_pmap_get_cpu_si (map, "ONE"); - if (x != _processor_number) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)_processor_number); - x = _stp_pmap_get_cpu_si (map, "TWO"); - if (x != 10 * _processor_number + 1) - printf("ERROR: Got %lld when expected %lld\n", x, (long long)(10 * _processor_number + 1)); - x = _stp_pmap_get_cpu_si (map, "FOUR"); - if (x != 1LL) - printf("ERROR: Got %lld when expected %lld\n", x, 1LL); - } - - /* now print the per-cpu data */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - printf("CPU #%d\n", _processor_number); - _stp_pmap_printn_cpu (map,0, "map[%1s] = %d", _processor_number); - } - _processor_number = 0; - - /* print the aggregated data */ - _stp_pmap_print(map,"map[%1s] = %d"); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/pmaps/size.c b/runtime/tests/pmaps/size.c deleted file mode 100644 index be8b4590..00000000 --- a/runtime/tests/pmaps/size.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "runtime.h" - -/* test of _stp_pmap_size() */ - -/* It's not clear this would ever be used in the systemtap language. - It would be useful as an array of counters. */ - -#define VALUE_TYPE INT64 -#define KEY1_TYPE INT64 -#include "pmap-gen.c" - -#include "map.c" - -#define check(map,num) \ - { \ - int size = _stp_pmap_size(map); \ - if (size != num) \ - printf("ERROR at line %d: expected size %d and got %d instead.\n", __LINE__, num, size); \ - } - -int main () -{ - PMAP map = _stp_pmap_new_ii(8); - int64_t x; - - check(map,0); - - /* put some data in. _processor_number is a global hack that allows */ - /* us to set the current emulated cpu number for our userspace tests. */ - /* Note that we set values based on the cpu number just to show that */ - /* different values are stored in each cpu */ - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_add_ii(map, 1, _processor_number); - _stp_pmap_add_ii(map, 2, 10 *_processor_number + 1); - _stp_pmap_add_ii(map, 3, _processor_number * _processor_number); - _stp_pmap_add_ii(map, 4, 1); - } - _processor_number = 0; - - check(map,4*NR_CPUS-2); - - _stp_pmap_add_ii(map, 1, 1); - _stp_pmap_add_ii(map, 3, 1); - check(map,4*NR_CPUS); - - _stp_pmap_add_ii(map, 5, 100); - check(map,4*NR_CPUS+1); - - _processor_number = 1; - _stp_pmap_add_ii(map, 5, 100); - check(map,4*NR_CPUS+2); - - _stp_pmap_set_ii(map, 5, 0); - check(map,4*NR_CPUS+1); - - _processor_number = 0; - _stp_pmap_set_ii(map, 5, 0); - check(map,4*NR_CPUS); - - for (_processor_number = 0; _processor_number < NR_CPUS; _processor_number++) { - _stp_pmap_set_ii(map, 1, 0); - _stp_pmap_set_ii(map, 2, 0); - _stp_pmap_set_ii(map, 3, 0); - _stp_pmap_set_ii(map, 4, 0); - } - _processor_number = 0; - check(map,0); - - _stp_pmap_del (map); - return 0; -} - diff --git a/runtime/tests/string/Makefile b/runtime/tests/string/Makefile deleted file mode 100644 index c396c132..00000000 --- a/runtime/tests/string/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -default: tests - -tests: - tclsh all.tcl - diff --git a/runtime/tests/string/all.tcl b/runtime/tests/string/all.tcl deleted file mode 100644 index 23757202..00000000 --- a/runtime/tests/string/all.tcl +++ /dev/null @@ -1,4 +0,0 @@ -package require tcltest -namespace import -force tcltest::* -tcltest::testsDirectory [file dir [info script]] -tcltest::runAllTests diff --git a/runtime/tests/string/print_cstr.c b/runtime/tests/string/print_cstr.c deleted file mode 100644 index 2de0f592..00000000 --- a/runtime/tests/string/print_cstr.c +++ /dev/null @@ -1,56 +0,0 @@ -/* test of _stp_print_cstr() */ - -/* use very small buffer size for testing */ -#define STP_PRINT_BUF_LEN 20 -#include "runtime.h" - -int main () -{ - /* can we see output? */ - _stp_print_cstr("ABCDE\n"); - _stp_print_flush(); - - - /* overflow */ - _stp_print_cstr("1234567890123456789012345\n"); - _stp_print_cstr("XYZZY\n"); - _stp_print_flush(); - - /* small string then overflow string */ - _stp_print_cstr("XYZZY\n"); - _stp_print_cstr("1234567890123456789012345"); - _stp_print_cstr("\n"); - _stp_print_flush(); - - /* two small string that overflow */ - _stp_print_cstr("abcdefghij"); - _stp_print_cstr("1234567890"); - _stp_print_cstr("\n"); - _stp_print_flush(); - - /* two small string that overflow */ - _stp_print_cstr("abcdefghij"); - _stp_print_cstr("1234567890X"); - _stp_print_cstr("\n"); - _stp_print_flush(); - - _stp_print_cstr("12345\n"); - _stp_print_cstr("67890\n"); - _stp_print_cstr("abcde\n"); - _stp_print_flush(); - _stp_print_flush(); - _stp_print_cstr("12345"); - _stp_print_cstr("67890"); - _stp_print_cstr("abcde"); - _stp_print_cstr("fghij"); - _stp_print_cstr("\n"); - _stp_print_flush(); - - /* null string */ - _stp_print_cstr(""); - _stp_print_flush(); - _stp_print_cstr(""); - _stp_print_cstr("Q\n"); - _stp_print_flush(); - return 0; -} diff --git a/runtime/tests/string/printf_A.c b/runtime/tests/string/printf_A.c deleted file mode 100644 index e6c1a93f..00000000 --- a/runtime/tests/string/printf_A.c +++ /dev/null @@ -1,56 +0,0 @@ -/* basic printf tests */ - -/* use very small buffer size for testing */ -#define STP_PRINT_BUF_LEN 20 -#include "runtime.h" - -int main () -{ - /* can we see output? */ - _stp_printf("ABCDE\n"); - _stp_print_flush(); - - - /* overflow */ - _stp_printf("1234567890123456789012345\n"); - _stp_printf("XYZZY\n"); - _stp_print_flush(); - - /* small string then overflow string */ - _stp_printf("XYZZY\n"); - _stp_printf("1234567890123456789012345"); - _stp_printf("\n"); - _stp_print_flush(); - - /* two small string that overflow */ - _stp_printf("abcdefghij"); - _stp_printf("1234567890"); - _stp_printf("\n"); - _stp_print_flush(); - - /* two small string that overflow */ - _stp_printf("abcdefghij"); - _stp_printf("1234567890X"); - _stp_printf("\n"); - _stp_print_flush(); - - _stp_printf("12345\n"); - _stp_printf("67890\n"); - _stp_printf("abcde\n"); - _stp_print_flush(); - _stp_print_flush(); - _stp_printf("12345"); - _stp_printf("67890"); - _stp_printf("abcde"); - _stp_printf("fghij"); - _stp_printf("\n"); - _stp_print_flush(); - - /* null string */ - _stp_printf(""); - _stp_print_flush(); - _stp_printf(""); - _stp_printf("Q\n"); - _stp_print_flush(); - return 0; -} diff --git a/runtime/tests/string/printf_B.c b/runtime/tests/string/printf_B.c deleted file mode 100644 index b9bbe170..00000000 --- a/runtime/tests/string/printf_B.c +++ /dev/null @@ -1,37 +0,0 @@ -/* more printf tests */ - -/* use very small buffer size for testing */ -#define STP_PRINT_BUF_LEN 20 -#include "runtime.h" - -#define LLONG_MAX 9223372036854775807LL -#define LLONG_MIN (-LLONG_MAX - 1LL) - - -int main () -{ - int i; - - /* a couple of loops showing continuous output */ - for (i = 0; i < 20; i++) - _stp_sprintf(_stp_stdout, "i=%d ", i); - _stp_printf("\n"); - _stp_print_flush(); - - for (i = 0; i < 5; i++) - _stp_printf("[%d %d %d] ", i, i*i, i*i*i); - _stp_printf("\n"); - _stp_print_flush(); - - int64_t x,y; - x = LLONG_MAX; - y = LLONG_MIN; - - _stp_printf("%lld ",x); - _stp_printf("(%llx) ", x); - _stp_printf("%lld ",y); - _stp_printf("(%llx) ", y); - _stp_printf("\n"); - _stp_print_flush(); - return 0; -} diff --git a/runtime/tests/string/string.test b/runtime/tests/string/string.test deleted file mode 100644 index 348b6b1f..00000000 --- a/runtime/tests/string/string.test +++ /dev/null @@ -1,89 +0,0 @@ -package require tcltest -namespace import -force tcltest::* - -cd $tcltest::testsDirectory - -set CFLAGS "-Os" -set KPATH "/lib/modules/[exec uname -r]/build/include" -set MPATH "/lib/modules/[exec uname -r]/build/include/asm/mach-default" -set PATH "../../user" - -test printf_A {Basic printf test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test printf_A.c -} -body { - exec ./test -} -result {ABCDE -12345678901234567890XYZZY -XYZZY -12345678901234567890 -abcdefghij1234567890 -abcdefghij1234567890X -12345 -67890 -abcde -1234567890abcdefghij -Q} - -test printf_B {More printf test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test printf_B.c -} -body { - exec ./test -} -result {i=0 i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9 i=10 i=11 i=12 i=13 i=14 i=15 i=16 i=17 i=18 i=19 -[0 0 0] [1 1 1] [2 4 8] [3 9 27] [4 16 64] -9223372036854775807 (7fffffffffffffff) -9223372036854775808(8000000000000000) } - -test print_cstr {Test of _stp_print_cstr()} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test print_cstr.c -} -body { - exec ./test -} -result {ABCDE -12345678901234567890XYZZY -XYZZY -12345678901234567890 -abcdefghij1234567890 -abcdefghij1234567890X -12345 -67890 -abcde -1234567890abcdefghij -Q} - -test string1 {Basic String test} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test string1.c -} -body { - exec ./test -} -result {Hello worldRed HatIntelIBM -Hello world / Red Hat / Intel / IBM / -Red Hat Inc. -Hello world Red Hat -IntelIBM} - -test string2 {More String tests} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test string2.c -} -body { - exec ./test -} -result {ABCDE -1234567890123456789 -XYZZY -1234567890123 -abcdefghij123456789 -abcdefghij123456789 -12345 -67890 -abcde -1234567890abcdefghi -Q} -test string3 {Even More String tests} -setup { - exec gcc $CFLAGS -I $KPATH -I $PATH -I $MPATH -o test string3.c -} -body { - exec ./test -} -result {1234567890abcABCDEvwxyz -abcde -1234567890abcde -1234567890abcdeABCD -1234567890abcdeABCD -ABCDEvwxyz} - -exec rm test - -cleanupTests diff --git a/runtime/tests/string/string1.c b/runtime/tests/string/string1.c deleted file mode 100644 index 48773e5f..00000000 --- a/runtime/tests/string/string1.c +++ /dev/null @@ -1,44 +0,0 @@ -/* test of Strings */ - -/* use very small buffer size for testing */ -#define STP_PRINT_BUF_LEN 20 -#define STP_NUM_STRINGS 4 -#include "runtime.h" - -int main () -{ - String str[4]; - int i; - - for (i = 0; i < 4; i++) - str[i] = _stp_string_init (i); - - _stp_sprintf(str[0], "Hello world"); - _stp_sprintf(str[1], "Red Hat"); - _stp_sprintf(str[2], "Intel"); - _stp_sprintf(str[3], "IBM"); - - for (i = 0; i < 4; i++) - _stp_print(str[i]); - _stp_print_cstr("\n"); - - for (i = 0; i < 4; i++) { - _stp_print(str[i]); - _stp_print(" / "); - } - _stp_print_cstr("\n"); - - _stp_string_cat_cstr (str[1], " Inc."); - _stp_print(str[1]); - _stp_print("\n"); - - _stp_string_cat_cstr (str[0], " "); - _stp_string_cat_string (str[0], str[1]); - _stp_print(str[0]); - _stp_print("\n"); - - _stp_sprintf(str[2], "%s\n", _stp_string_ptr(str[3])); - _stp_print(str[2]); - _stp_print_flush(); - return 0; -} diff --git a/runtime/tests/string/string2.c b/runtime/tests/string/string2.c deleted file mode 100644 index ccf3997a..00000000 --- a/runtime/tests/string/string2.c +++ /dev/null @@ -1,68 +0,0 @@ -/* test of Strings */ - -/* use very small buffer size for testing */ -#define STP_STRING_SIZE 20 -#define STP_NUM_STRINGS 1 -#include "runtime.h" - -int main () -{ - String str = _stp_string_init (0); - - /* can we see output? */ - _stp_sprintf(str, "ABCDE\n"); - _stp_print(str); - - - /* overflow */ - str = _stp_string_init (0); - _stp_sprintf(str, "1234567890123456789012345\n"); - _stp_sprintf(str, "XYZZY\n"); - _stp_print(str); - _stp_printf("\n"); - - /* small string then overflow string */ - str = _stp_string_init (0); - _stp_sprintf(str,"XYZZY\n"); - _stp_sprintf(str,"1234567890123456789012345"); - _stp_print(str); - _stp_printf("\n"); - - /* two small string that overflow */ - str = _stp_string_init (0); - _stp_sprintf(str,"abcdefghij"); - _stp_sprintf(str,"123456789"); - _stp_print(str); - _stp_printf("\n"); - - /* two small string that overflow */ - str = _stp_string_init (0); - _stp_sprintf(str,"abcdefghij"); - _stp_sprintf(str,"1234567890X"); - _stp_print(str); - _stp_printf("\n"); - - str = _stp_string_init (0); - _stp_sprintf(str,"12345\n"); - _stp_sprintf(str,"67890\n"); - _stp_sprintf(str,"abcde\n"); - _stp_print(str); - - str = _stp_string_init (0); - _stp_sprintf(str,"12345"); - _stp_sprintf(str,"67890"); - _stp_sprintf(str,"abcde"); - _stp_sprintf(str,"fghij"); - _stp_print(str); - _stp_printf("\n"); - - /* null string */ - str = _stp_string_init (0); - _stp_sprintf(str,""); - _stp_sprintf(str,""); - _stp_sprintf(str,"Q\n"); - _stp_print(str); - - _stp_print_flush(); - return 0; -} diff --git a/runtime/tests/string/string3.c b/runtime/tests/string/string3.c deleted file mode 100644 index 3982a8e1..00000000 --- a/runtime/tests/string/string3.c +++ /dev/null @@ -1,45 +0,0 @@ -/* test of Strings */ - -/* use very small buffer size for testing */ -#define STP_STRING_SIZE 20 -#define STP_NUM_STRINGS 4 -#include "runtime.h" - -int main () -{ - String str[4]; - int i; - - for (i = 0; i < 4; i++) - str[i] = _stp_string_init (i); - - _stp_string_cat(str[0], "1234567890"); - _stp_string_cat(str[1], "abc"); - _stp_string_cat(str[2], "ABCDE"); - _stp_string_cat(str[3], "vwxyz"); - - for (i = 0; i < 4; i++) - _stp_print(str[i]); - _stp_print("\n"); - - _stp_string_cat (str[1], "de"); - _stp_print(str[1]); - _stp_print("\n"); - - _stp_string_cat(str[0], str[1]); - _stp_print(str[0]); - _stp_print("\n"); - - _stp_string_cat(str[0], str[2]); - _stp_print(str[0]); - _stp_print("\n"); - - _stp_string_cat(str[0], str[2]); - _stp_print(str[0]); - _stp_print("\n"); - - _stp_sprintf(str[2], "%s\n", _stp_string_ptr(str[3])); - _stp_print(str[2]); - _stp_print_flush(); - return 0; -} diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 9d0ba162..2e59ff90 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,14 @@ +2008-06-13 Wenji Huang <wenji.huang@oracle.com> + + * control.c (_stp_ctl_write_dbug): Remove STP_UNWIND support. + +2008-06-03 Frank Ch. Eigler <fche@elastic.org> + + PR 6429 + * symbols.c (_stp_init_modules): Don't ask stapio for unwind data. + * control.c (_stp_ctl_write_cmd): Remove STP_UNWIND support. + * transport_msgs.h (STP_UNWIND): Remove declaration. + 2008-04-30 Masami Hiramatsu <mhiramat@redhat.com> PR 5645 diff --git a/runtime/transport/control.c b/runtime/transport/control.c index ca7edf79..9319b9ca 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -36,9 +36,6 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz #endif switch (type) { - case STP_UNWIND: - _stp_do_unwind_data(buf, count); - break; case STP_START: if (started == 0) { struct _stp_msg_start st; @@ -103,10 +100,6 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; - case STP_UNWIND: - snprintf(buf, sizeof(buf), "%s", (char *)data); - _dbug("sending STP_UNWIND %s [len=%d]\n", buf, len); - break; default: _dbug("ERROR: unknown message type: %d\n", type); break; diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 087bf893..4a3c4e17 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -196,7 +196,11 @@ static int _stp_init_kernel_symbols(void) _stp_num_modules = 1; /* Note: this mapping is used by kernel/_stext pseudo-relocations. */ + #ifdef __powerpc__ + _stp_modules[0]->text = _stp_kallsyms_lookup_name(".__start"); + #else _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); + #endif if (_stp_modules[0]->text == 0) { _dbug("Lookup of _stext failed. Exiting.\n"); return -1; @@ -399,6 +403,22 @@ static int _stp_section_is_interesting(const char *name) return ret; } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) +struct module_sect_attr +{ + struct module_attribute mattr; + char *name; + unsigned long address; +}; + +struct module_sect_attrs +{ + struct attribute_group grp; + unsigned int nsections; + struct module_sect_attr attrs[0]; +}; +#endif + /* Create a new _stp_module and load the symbols */ static struct _stp_module *_stp_load_module_symbols(struct module *mod) { @@ -609,7 +629,7 @@ static int _stp_init_modules(void) /* unlocks the list */ modules_op->stop(NULL, NULL); -#ifdef STP_USE_DWARF_UNWINDER +#if 0 /* def STP_USE_DWARF_UNWINDER */ /* now that we have all the modules, ask for their unwind info */ { unsigned long flags; diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 5f385565..27476e76 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -23,7 +23,6 @@ enum STP_EXIT, STP_OOB_DATA, STP_SYSTEM, - STP_UNWIND, STP_TRANSPORT, STP_CONNECT, STP_DISCONNECT, @@ -44,7 +43,6 @@ static const char *_stp_command_name[] = { "STP_EXIT", "STP_OOB_DATA", "STP_SYSTEM", - "STP_UNWIND", "STP_TRANSPORT", "STP_CONNECT", "STP_DISCONNECT", @@ -25,6 +25,7 @@ extern "C" { struct match_node; struct stapfile; struct vardecl; +struct token; struct functiondecl; struct derived_probe; struct be_derived_probe_group; @@ -42,6 +43,7 @@ struct embeddedcode; struct translator_output; struct unparser; struct semantic_error; +struct module_cache; // XXX: a generalized form of this descriptor could be associated with @@ -164,11 +166,17 @@ struct systemtap_session // List of libdwfl module names to extract symbol/unwind data for. std::set<std::string> unwindsym_modules; + struct module_cache* module_cache; std::set<std::string> seen_errors; + std::set<std::string> seen_warnings; unsigned num_errors () { return seen_errors.size(); } + // void print_error (const parse_error& e); + const token* last_token; + void print_token (std::ostream& o, const token* tok); void print_error (const semantic_error& e); + void print_warning (const std::string& w, const token* tok = 0); // reNB: new POD members likely need to be explicitly cleared in the ctor. }; diff --git a/stap-client b/stap-client new file mode 100755 index 00000000..42402a27 --- /dev/null +++ b/stap-client @@ -0,0 +1,606 @@ +#!/bin/bash + +# Compile server client 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 examines the systemtap command line and packages the files and +# information needed to execute the command. This is then sent to a trusted +# systemtap server which will process the request and return the resulting +# kernel module (if requested) and any other information generated by the +# request. If a kernel module is generated, this script will load the module +# and execute it using 'staprun', if requested. + +#----------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------- +# function: configuration +function configuration { + tmpdir_prefix_client=stap.client + tmpdir_prefix_server=stap.server + avahi_service_tag=_stap._tcp +} + +# function: initialization +function initialization { + wd=`pwd` + umask 0 + + # Default options settings + p_phase=5 + v_level=0 + keep_temps=0 + + # Create a temporary directory to package things in + # Do this before parsing the command line so that there is a place + # to put -I and -R directories. + tmpdir_client=`mktemp -dt $tmpdir_prefix_client.XXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $tmpdir_client + tmpdir_env=`dirname $tmpdir_client` +} + +# function: parse_options [ STAP-OPTIONS ] +# +# Examine the command line. We need not do much checking, but we do need to +# parse all options in order to discover the ones we're interested in. +# The server will take care of most situations and return the appropriate +# output. +# +function parse_options { + cmdline= + while test $# != 0 + do + advance_p=0 + dash_seen=0 + + # Start of a new token. + first_token=$1 + until test $advance_p != 0 + do + # Identify the next option + first_char=`expr "$first_token" : '\(.\).*'` + if test $dash_seen = 0; then + if test "$first_char" = "-"; then + if test "$first_token" != "-"; then + # It's not a lone dash, so it's an option. Remove the dash. + first_token=`expr "$first_token" : '-\(.*\)'` + dash_seen=1 + first_char=`expr "$first_token" : '\(.\).*'` + cmdline="$cmdline -" + fi + fi + if test $dash_seen = 0; then + # The dash has not been seen. This is either the script file + # name or an arument to be passed to the probe module. + # If this is the first time, and -e has not been specified, + # then it could be the name of the script file. + if test "X$e_script" = "X" -a "X$script_file" = "X"; then + script_file=$first_token + fi + advance_p=$(($advance_p + 1)) + cmdline="$cmdline $first_token" + break + fi + fi + + # We are at the start of an option. Look at the first character. + case $first_char in + c) + get_arg $first_token "$2" + process_c "$stap_arg" + ;; + D) + get_arg $first_token $2 + cmdline="${cmdline}D '$stap_arg'" + ;; + e) + get_arg $first_token "$2" + process_e "$stap_arg" + ;; + I) + get_arg $first_token $2 + process_I $stap_arg + ;; + k) + keep_temps=1 + ;; + l) + get_arg $first_token $2 + cmdline="${cmdline}l '$stap_arg'" + ;; + m) + get_arg $first_token $2 + cmdline="${cmdline}m $stap_arg" + ;; + o) + get_arg $first_token $2 + process_o $stap_arg + ;; + p) + get_arg $first_token $2 + process_p $stap_arg + ;; + r) + get_arg $first_token $2 + cmdline="${cmdline}r $stap_arg" + ;; + R) + get_arg $first_token $2 + process_R $stap_arg + ;; + s) + get_arg $first_token $2 + cmdline="${cmdline}s $stap_arg" + ;; + v) + v_level=$(($v_level + 1)) + ;; + x) + get_arg $first_token $2 + cmdline="${cmdline}x $stap_arg" + ;; + *) + # An unknown or unimportant flag. Ignore it, but pass it on to the server. + ;; + esac + + if test $advance_p = 0; then + # Just another flag character. Consume it. + cmdline="$cmdline$first_char" + first_token=`expr "$first_token" : '.\(.*\)'` + if test "X$first_token" = "X"; then + advance_p=$(($advance_p + 1)) + fi + fi + done + + # Consume the arguments we just processed. + while test $advance_p != 0 + do + shift + advance_p=$(($advance_p - 1)) + done + done + + # 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` + cmdline=`echo $cmdline | sed s,$script_file,script/$local_name,` + fi +} + +# function: get_arg FIRSTWORD SECONDWORD +# +# Collect an argument to the given option +function get_arg { + # Remove first character. + local opt=`expr "$1" : '\(.\).*'` + local first=`expr "$1" : '.\(.*\)'` + + # Advance to the next token, if the first one is exhausted. + if test "X$first" = "X"; then + shift + advance_p=$(($advance_p + 1)) + first=$1 + fi + + test "X$first" != "X" || \ + fatal "Missing argument to -$opt" + + stap_arg="$first" + advance_p=$(($advance_p + 1)) +} + +# function: process_c ARGUMENT +# +# Process the -c flag. +function process_c { + c_cmd="$1" + cmdline="${cmdline}c '$1'" +} + +# function: process_e ARGUMENT +# +# Process the -e flag. +function process_e { + # Only the first -e option is recognized and it overrides any script file name + # which may have already been identified. + if test "X$e_script" = "X"; then + e_script="$1" + script_file= + fi + cmdline="${cmdline}e '$1'" +} + +# function: process_I ARGUMENT +# +# Process the -I flag. +function process_I { + local local_name=`include_file_or_directory tapsets $1` + test "X$local_name" != "X" || return + cmdline="${cmdline}I $local_name" +} + +# function: process_o ARGUMENT +# +# Process the -o flag. +function process_o { + stdout_redirection="> $1" + cmdline="${cmdline}o $1" +} + +# function: process_p ARGUMENT +# +# Process the -p flag. +function process_p { + p_phase=$1 + cmdline="${cmdline}p '$1'" +} + +# function: process_R ARGUMENT +# +# Process the -R flag. +function process_R { + local local_name=`include_file_or_directory runtime $1` + test "X$local_name" != "X" || return + cmdline="${cmdline}R $local_name" +} + +# function: include_file_or_directory PREFIX NAME +# +# 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 + 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`" + ln -s /$local_name $tmpdir_client/$1/$local_name || \ + fatal "ERROR: could not link $tmpdir_client/$1/$local_name to /$local_name" + echo $local_name +} + +# function: generate_client_temp_name NAME +# +# Generate the name to be used for the given file/directory relative to the +# client's temporary directory. +function generate_client_temp_name { + # Transform the name into a fully qualified path name + local full_name=`echo $1 | sed "s,^\\\([^/]\\\),$wd/\\\\1,"` + + # The same name without the initial / or trailing / + local local_name=`echo $full_name | sed 's,^/\(.*\),\1,'` + local_name=`echo $local_name | sed 's,\(.*\)/$,\1,'` + echo $local_name +} + +# function: create_request +# +# Add information to the client's temp directory representing the request +# to the server. +function create_request { + # Work in our temporary directory + cd $tmpdir_client + + 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/- + 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 +} + +# function client_sysinfo +# +# Generate the client's sysinfo and echo it to stdout +function client_sysinfo { + if test "X$sysinfo_client" = "X"; then + # Get the stap version + stap_version=`stap -V 2>&1 | grep version` + # Remove the number before the first slash + stap_version=`expr "$stap_version" : '.*version [^/]*/\([0-9./]*\).*'` + # Add some info from uname + sysinfo_client="stap $stap_version `uname -sr`" + fi + echo $sysinfo_client +} + +# function: package_request +# +# Package the client's temp directory into a form suitable for sending to the +# server. +function package_request { + # Package up the temporary directory into a tar file + cd $tmpdir_env + + local tmpdir_client_base=`basename $tmpdir_client` + tar_client=$tmpdir_env/`mktemp $tmpdir_client_base.tgz.XXXXXX` || \ + fatal "ERROR: cannot create temporary file " $tar_client + + tar -czhf $tar_client $tmpdir_client_base || \ + fatal "ERROR: tar of request tree, $tmpdir_client, failed" + + tar_server=$tmpdir_env/`mktemp $tmpdir_prefix_server.tgz.XXXXXX` || \ + fatal "ERROR: cannot create temporary file " $tar_server +} + +# function: send_request +# +# Notify the server and then send $tar_client to the server as $tar_server +# The protocol is: +# client -> "request: $tmpdir_client" +# server -> "send: $tar_server" +# client: rsync local:$tar_client server:$tar_server +# client -> "waiting:" +# +# $tmpdir_client is provided on the request so that the server knows what +# the tar file will expand to. +function send_request { + echo "request: `basename $tmpdir_client`" >&3 + + read <&3 + local line=$REPLY + check_server_error $line + + local tar_dest=`expr "$line" : 'send: \([^ ]*\)$'` + test "X$tar_dest" == "X" && \ + fatal "ERROR: destination tar file not provided" + + rsync -essh -a --delete $tar_client root@$server:$tar_dest || \ + fatal "ERROR: rsync of client request, $tar_client to $server:$tar_dest, failed" + + echo "waiting:" >&3 +} + +# function: receive_response +# +# Wait for a response from the server indicating the results of our request. +# The protocol is: +# server -> "sending: remote-tar-name server-tempdir-name stap-tempdir-name" +# client -> "OK" +function receive_response { + read <&3 + local line=$REPLY + check_server_error $line + + tar_dest=`expr "$line" : 'sending: \([^ ]*\) [^ ]* [^ ]*$'` + test "X$tar_dest" == "X" && \ + fatal "ERROR: server response remote file is missing" + + tmpdir_server=`expr "$line" : 'sending: [^ ]* \([^ ]*\) [^ ]*$'` + test "X$tmpdir_server" == "X" && \ + fatal "ERROR: server response temp dir is missing" + + tmpdir_stap=`expr "$line" : 'sending: [^ ]* [^ ]* \([^ ]*\)$'` + test "X$tmpdir_stap" == "X" && \ + fatal "ERROR: server response stap temp dir is missing" + + + # Retrieve the file + rsync -essh -a --delete root@$server:$tar_dest $tar_server || \ + fatal "ERROR: rsync of server response, $server:$tar_dest to $tar_server, failed" + echo "OK" >&3 +} + +# function: unpack_response +# +# Unpack the tar file received from the server and make the contents available +# for printing the results and/or running 'staprun'. +function unpack_response { + # Unpack the server output directory + cd $tmpdir_client + tar -xzf $tar_server || \ + fatal "ERROR: Unpacking of server response, $tar_server, failed" + + # Create a local location for the server response. + local local_tmpdir_server_base=`basename $tar_server | sed 's,\.tgz,,'` + local local_tmpdir_server=`mktemp -dt $local_tmpdir_server_base.XXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $local_tmpdir_server + + # Move the systemtap temp directory to our 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=$local_tmpdir_server/$tmpdir_stap + fi + + # Move the extracted tree to our local location + mv $tmpdir_server/* $local_tmpdir_server + rm -fr $tmpdir_server + tmpdir_server=$local_tmpdir_server +} + +# function: find_and_connect_to_server +# +# Find and establish connection with a compatibale stap server. +function find_and_connect_to_server { + # Find a server + server=`avahi-browse $avahi_service_tag --terminate -r 2>/dev/null | match_server` + test "X$server" != "X" || \ + fatal "ERROR: cannot find a server" + + port=`expr "$server" : '[^/]*/\(.*\)'` + server=`expr "$server" : '\([^/]*\)/.*'` + + # 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 +} + +# function: match_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 + 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" : '\[\"\([^]]*\)\"\]'` + sysinfo_server=`expr "$sysinfo_server" : '[^/]*/\(.*\)'` + ;; + * ) + break ;; + esac + done + + # It is a stap server, but is it compatible? + sysinfo_server="stap $sysinfo_server" + if test "$sysinfo_server" != "`client_sysinfo`"; then + continue + fi + + if test "X$server_ip" != "X"; then + break + fi + done + + echo $server_ip/$port +} + +# function: disconnect_from_server +# +# Disconnect from the server. +function disconnect_from_server { + # Close the connection to the server. + exec 3<&- +} + +# function: stream_output +# +# Write the stdout and stderr from the server to stdout and stderr respectively. +function stream_output { + # Output stdout and stderr as directed + cd $local_tmpdir_server + cat ${tmpdir_server}/stderr >&2 + eval cat ${tmpdir_server}/stdout $stdout_redirection +} + +# function: maybe_call_staprun +# +# Call staprun using the module returned from the server, if requested. +function maybe_call_staprun { + if test $p_phase = 5; then + for ((--v_level; $v_level > 0; --v_level)) + do + staprun_opts="$staprun_opts -v" + done + staprun $staprun_opts \ + $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'` + fi +} + +# function: check_server_error SERVER_RESPONSE +# +# Check the given server response for an error message. +function check_server_error { + echo $1 | grep -q "^ERROR:" && \ + fatal "Server:" "$@" +} + +# function: fatal [ MESSAGE ] +# +# Fatal error +# Prints its arguments to stderr and exits +function fatal { + echo $0: "$@" >&2 + cat <&3 >&2 + cleanup + exit 1 +} + +# function cleanup +# +# Cleanup work files unless asked to keep them. +function cleanup { + # Clean up. + cd $tmpdir_env + if test $keep_temps != 1; then + rm -fr $tmpdir_client + rm -f $tar_client + rm -f $tar_server + rm -fr $tmpdir_server + fi +} + +#----------------------------------------------------------------------------- +# Beginning of main line execution. +#----------------------------------------------------------------------------- +configuration +initialization +parse_options "$@" +create_request +package_request +find_and_connect_to_server +send_request +receive_response +unpack_response +disconnect_from_server +stream_output +maybe_call_staprun +cleanup + +exit 0 diff --git a/stap-server b/stap-server new file mode 100755 index 00000000..1a2e7918 --- /dev/null +++ b/stap-server @@ -0,0 +1,436 @@ +#!/bin/bash + +# Compile server 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 unpacks the tar file provided on stdin and uses the information +# contained in the unpacked tree to build the requested systemtap kernel module. +# This module is then written to stdout. + +#----------------------------------------------------------------------------- +# Helper functions. +#----------------------------------------------------------------------------- +# function: configuration +function configuration { + # Configuration + tmpdir_prefix_client=stap.client + tmpdir_prefix_server=stap.server +} + +# function: initialization +function initialization { + # Initialization + wd=`pwd` + + # Default options settings + p_phase=5 + keep_temps=0 + + # Make a temp directory to work in. + tmpdir_server=`mktemp -dt $tmpdir_prefix_server.XXXXXX` || \ + fatal "ERROR: cannot create temporary directory " $tmpdir_server + tmpdir_env=`dirname $tmpdir_server` +} + +# function: receive_request +# +# Receive a tar file representing the request from the client: +# The protocol is: +# client -> "request: $tmpdir_client" +# server -> "send: $tar_client" +# client: copies file to server:$tar_client +# client -> "waiting:" +# +# $tmpdir_client is provided on the request so that we know what +# the tar file will expand to. +function receive_request { + cd $tmpdir_server + + # Request from the client is on stdin + read + line=$REPLY + + # Extract the name of the client's temp directory. + tmpdir_client=`expr "$line" : 'request: \([^ ]*\)$'` + test "X$tmpdir_client" == "X" && \ + fatal "ERROR: client request temp dir name is missing" $tmpdir_server + tmpdir_client=$tmpdir_server/$tmpdir_client + + # Create the client's temp dir now to guarantee that it won't clash with + # any files we need to create later. + mkdir $tmpdir_client || \ + fatal "ERROR: cannot create client temp dir" $tmpdir_client + + # Create a place to receive the client's tar file + tar_client=`mktemp -t $tmpdir_prefix_client.tgz.XXXXXX` || \ + fatal "ERROR: cannot create temporary tar file " $tar_client + + # Request that the file be sent. + echo "send: $tar_client" + + # Wait for confirmation that the tar file has arrived via rysnc + read + line=$REPLY + test "X$line" = "Xwaiting:" || \ + fatal "ERROR: client send confirmation, '$line', is incorrect" +} + +# function: unpack_request +# +# Unpack the tar file received from the client and make the contents +# available for use when running 'stap' +function unpack_request { + cd $tmpdir_server + + # Unpack the tar file. + tar -xzf $tar_client || \ + fatal "ERROR: cannot unpack tar archive $tar_client" + + # Move the client's temp directory to a local temp location + local tmpdir_client_base=`basename $tar_client | sed 's,\.tgz,,'` + local local_tmpdir_client=`mktemp -dt $tmpdir_client_base.XXXXXX` || \ + fatal "ERROR: cannot create temporary tar file " $local_tmpdir_client + mv $tmpdir_client/* $local_tmpdir_client + rm -fr $tmpdir_client + tmpdir_client=$local_tmpdir_client +} + +# function: check_request +# +# Examine the contents of the request to make sure that they are valid. +function check_request { + # Work in the temporary directory provided by the client + cd $tmpdir_client + + # Add the necessary info from files in our temporary directory. + cmdline=`read_data_file cmdline` + test "X$cmdline" != "X" || exit 1 + client_sysinfo=`read_data_file sysinfo` + test "X$client_sysinfo" != "X" || exit 1 + + # Extract the client's config info. + client_name=`expr "$client_sysinfo" : 'stap [^ ]* [^ ]* \([^ ]*\).*'` + client_sysinfo=`echo $client_sysinfo | sed s,$client_name,,` + + # Extract the server's config info. + server_sysinfo=`uname -sr` + server_name=`expr "$server_sysinfo" : '[^ ]* \([^ ]*\).*'` + server_sysinfo=`echo $server_sysinfo | sed s,$server_name,,` + local stap_version=`stap -V 2>&1 | grep version` + stap_version=`expr "$stap_version" : '.*version \([0-9./]*\).*'` + server_sysinfo="stap $stap_version $server_sysinfo" + + check_compatibility "$client_sysinfo" "$server_sysinfo" +} + +# function check_compaibility SYSINFO1 SYSINFO2 +# +# Make sure that systemtap as described by SYSINFO1 and SYSINFO2 are compaible +function check_compatibility { + # TODO: This needs work + # - In stap version x/y, require that the y matches + # - Make sure the linux kernel matches exactly + local sysinfo1=`echo $1 | sed 's,stap [^/]*/,stap ,'` + local sysinfo2=`echo $2 | sed 's,stap [^/]*/,stap ,'` + + if test "$sysinfo1" != "$sysinfo2"; then + error "ERROR: system configuration mismatch" + error " client: $sysinfo1" + fatal " server: $sysinfo2" + fi +} + +# function: read_data_file PREFIX +# +# Find a file whose name matches '$1.??????' 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" +} + +# function: parse_options [ STAP-OPTIONS ] +# +# Examine the command line. We need not do much checking, but we do need to +# parse all options in order to discover the ones we're interested in. +function parse_options { + while test $# != 0 + do + advance_p=0 + dash_seen=0 + + # Start of a new token. + first_token=$1 + until test $advance_p != 0 + do + # Identify the next option + first_char=`expr "$first_token" : '\(.\).*'` + if test $dash_seen = 0; then + if test "$first_char" = "-"; then + if test "$first_token" != "-"; then + # It's not a lone dash, so it's an option. Remove the dash. + first_token=`expr "$first_token" : '-\(.*\)'` + dash_seen=1 + first_char=`expr "$first_token" : '\(.\).*'` + fi + fi + if test $dash_seen = 0; then + # The dash has not been seen. This is either the script file + # name or an arument to be passed to the probe module. + # If this is the first time, and -e has not been specified, + # then it could be the name of the script file. + if test "X$e_script" = "X" -a "X$script_file" = "X"; then + script_file=$first_token + fi + advance_p=$(($advance_p + 1)) + break + fi + fi + + # We are at the start of an option. Look at the first character. + case $first_char in + c) + get_arg $first_token "$2" + ;; + D) + get_arg $first_token $2 + ;; + e) + get_arg $first_token "$2" + process_e "$stap_arg" + ;; + I) + get_arg $first_token $2 + ;; + k) + keep_temps=1 + ;; + l) + get_arg $first_token $2 + ;; + m) + get_arg $first_token $2 + ;; + o) + get_arg $first_token $2 + ;; + p) + get_arg $first_token $2 + process_p $stap_arg + ;; + r) + get_arg $first_token $2 + ;; + R) + get_arg $first_token $2 + ;; + s) + get_arg $first_token $2 + ;; + x) + get_arg $first_token $2 + ;; + *) + # An unknown flag. Ignore it. + ;; + esac + + if test $advance_p = 0; then + # Just another flag character. Consume it. + first_token=`expr "$first_token" : '.\(.*\)'` + if test "X$first_token" = "X"; then + advance_p=$(($advance_p + 1)) + fi + fi + done + + # Consume the arguments we just processed. + while test $advance_p != 0 + do + shift + advance_p=$(($advance_p - 1)) + done + done +} + +# function: get_arg FIRSTWORD SECONDWORD +# +# Collect an argument to the given option +function get_arg { + # Remove first character. Advance to the next token, if the first one + # is exhausted. + local first=`expr "$1" : '.\(.*\)'` + if test "X$first" = "X"; then + shift + advance_p=$(($advance_p + 1)) + first=$1 + fi + + stap_arg="$first" + advance_p=$(($advance_p + 1)) +} + +# function: process_e ARGUMENT +# +# Process the -e flag. +function process_e { + if test "X$e_script" = "X"; then + e_script="$1" + script_file= + fi +} + +# function: process_p ARGUMENT +# +# Process the -p flag. +function process_p { + if test $1 -ge 1 -a $1 -le 5; then + p_phase=$1 + fi +} + +# function: call_stap +# +# Call 'stap' with the options provided. Don't run past phase 4. +function call_stap { + # Invoke systemtap. + # Use -k so we can return results to the client + # Limit to -p4. i.e. don't run the module + cd $tmpdir_client + if test $p_phase -gt 4; then + server_p_phase=4 + else + server_p_phase=$p_phase + fi + eval stap $cmdline -k -p $server_p_phase \ + >> $tmpdir_server/stdout \ + 2>> $tmpdir_server/stderr +} + +# function: create_response +# +# Add information to the server's temp directory representing the response +# to the client. +function create_response { + cd $tmpdir_server + + # Get the name of the stap temp directory, which was kept, from stderr. + 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 + # the user did request to keep it. + if test $keep_temps != 1; then + sed -i "/^Keeping temp/d" stderr + 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 +# +# Package the server's temp directory into a form suitable for sending to the +# client. +function package_response { + cd $tmpdir_env + # Create a place to generate our tar file of our temporary directory + local tmpdir_server_base=`basename $tmpdir_server` + tar_server=$tmpdir_env/`mktemp $tmpdir_server_base.tgz.XXXXXX` || \ + fatal "ERROR: cannot create temporary tar file " $tar_server + chmod +r $tar_server + + # Generate the tar file + tar -czphf $tar_server `basename $tmpdir_server` || \ + fatal "ERROR: tar of $tmpdir_server failed" +} + +# function: send_response +# +# Notify the client that $tar_server is ready and wait for the client to take +# it. +# The protocol is: +# server -> "sending: $tar_server $tmpdir_server $tmpdir_stap" +# client: copies file from server:$tar_server +# client -> "OK" +function send_response { + # TODO needed for rsync from client to work + chmod +r $tmpdir_server + + # Tell the client where to get it. + echo "sending: $tar_server `basename $tmpdir_server` `basename $tmpdir_stap`" + + # Wait for the confirmation + read + line=$REPLY + test $line = "OK" || \ + fatal "ERROR: client final confirmation, '$line' is incorrect" +} + +# function: fatal [ MESSAGE ] +# +# Fatal error +# Prints its arguments to stderr and exits +function fatal { + echo "$@" >&2 + cleanup + exit 1 +} + +# Non fatal error +# Prints its arguments to stderr but does not exit +function error { + echo "$@" >&2 +} + +# function cleanup +# +# Cleanup work files unless asked to keep them. +function cleanup { + # Clean up. + cd $tmpdir_env + if test $keep_temps != 1; then + rm -fr $tar_client + rm -fr $tmpdir_client + rm -fr $tar_server + rm -fr $tmpdir_server + rm -fr $tmpdir_stap + fi +} + +#----------------------------------------------------------------------------- +# Beginning of main line execution. +#----------------------------------------------------------------------------- +configuration +initialization +receive_request +unpack_request +check_request +eval parse_options $cmdline +call_stap +create_response +package_response +send_response +cleanup + +exit 0 @@ -1040,10 +1040,8 @@ RPM, unless overridden by the .I SYSTEMTAP_DEBUGINFO_PATH environment variable. The default value for this variable is .IR \-:.debug:/usr/lib/debug . -This path is interpreted by elfutils as a list of base directories of -which various subdirectories will be searched. The \- at the front -means to skip CRC matching for separated debug objects and is a small -performance win if no possible corruption is suspected. +Elfutils searches vmlinux in this path and it interprets the path as a base +directory of which various subdirectories will be searched for finding modules. .TP @prefix@/bin/staprun The auxiliary program supervising module loading, interaction, and @@ -1052,6 +1050,7 @@ unloading. .SH SEE ALSO .IR stapprobes (5), .IR stapfuncs (5), +.IR stapvars (5), .IR stapex (5), .IR awk (1), .IR gdb (1) diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 04e5ea17..acfb42f9 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -252,6 +252,9 @@ Return the probe point's module name, if known. target:long () Return the pid of the target process. .TP +user_mode:long () +Return 1 if the probe point occurred in user-mode. +.TP is_return:long () Return 1 if the probe point is a return probe. Deprecated. @@ -345,6 +348,11 @@ Return the maximum number of file handles for the given task. .SS CPU REGISTERS .TP +registers_valid:long () +Return 1 if register() and u_register() can be used +in the current context, or 0 otherwise. +For example, registers_valid() returns 0 when called from a begin or end probe. +.TP register:long (name:string) Return the value of the named CPU register, as it was saved when the current probe point was hit. @@ -368,7 +376,7 @@ segment registers: xcs/cs, xss/ss. For powerpc, the following names are recognized: r1, r2... r31, nip, msr, orig_gpr3, ctr, link, xer, ccr, softe, trap, -dar, dsisr, result; +dar, dsisr, result. .TP u_register:long (name:string) @@ -634,6 +642,20 @@ or SIG_ERR, it will return the address of the handler. signal_str(num) Returns the string representation of the given signal number. +.SS DEVICE +.TP +MAJOR:long(dev:long) +Extracts the major device number from a kernel device number (kdev_t). +.TP +MINOR:long(dev:long) +Extracts the minor device number from a kernel device number (kdev_t). +.TP +MKDEV:long(major:long, minor:long) +Creates a value that can be compared to a kernel device number (kdev_t). +.TP +usrdev2kerndev:long(dev:long) +Converts a user-space device number into the format used in the kernel. + .SH FILES .nh .IR @prefix@/share/systemtap/tapset diff --git a/stapprobes.5.in b/stapprobes.5.in index 3633fd39..5d400cb6 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -256,7 +256,12 @@ linux source directory, although an absolute path may be necessary for some kern If a relative pathname doesn't work, try absolute. .IP \(bu 4 Finally, the third part is optional if the file name part was given, -and identifies the line number in the source file, preceded by a ":". +and identifies the line number in the source file preceded by a ":" +or a "+". The line number is assumed to be an +absolute line number if preceded by a ":", or relative to the entry of +the function if preceded by a "+". +All the lines in the function can be matched with ":*". +A range of lines x through y can be matched with ":x-y". .PP As an alternative, PATTERN may be a numeric constant, indicating an (module-relative or kernel-_stext-relative) address. In guru mode @@ -309,12 +314,14 @@ All threads of that process will be probed. .PP Additional user-space probing is available in the following forms: .SAMPLE -process(PID).clone -process("PATH").clone -process(PID).exec -process("PATH").exec -process(PID).death -process("PATH").death +process(PID).begin +process("PATH").begin +process(PID).thread.begin +process("PATH").thread.begin +process(PID).end +process("PATH").end +process(PID).thread.end +process("PATH").thread.end process(PID).syscall process("PATH").syscall process(PID).syscall.return @@ -322,15 +329,16 @@ process("PATH").syscall.return .ESAMPLE .PP A -.B .clone -probe gets called when a thread described by PID or PATH creates a new -thread. +.B .begin +probe gets called when new process described by PID or PATH gets created. A -.B .exec -probe gets called when a thread described by PID or PATH returns from -.IR exec() . +.B .thread.begin +probe gets called when a new thread described by PID or PATH gets created. A -.B .death +.B .end +probe gets called when process described by PID or PATH dies. +A +.B .thread.end probe gets called when a thread described by PID or PATH dies. A .B .syscall @@ -490,7 +498,10 @@ refers to the first byte of the statement whose compiled instructions include the given address in the kernel. .TP kernel.statement("*@kernel/sched.c:2917") -refers to the statement of line 2917 within the "kernel/sched.c". +refers to the statement of line 2917 within "kernel/sched.c". +.TP +kernel.statement("bio_init@fs/bio.c+3") +refers to the statement at line bio_init+3 within "fs/bio.c". .TP syscall.*.return refers to the group of probe aliases with any name in the third position diff --git a/stapvars.5.in b/stapvars.5.in new file mode 100644 index 00000000..94e47667 --- /dev/null +++ b/stapvars.5.in @@ -0,0 +1,51 @@ +.\" -*- nroff -*- +.TH STAPVARS 5 @DATE@ "Red Hat" +.SH NAME +stapvars \- systemtap variables + +.SH DESCRIPTION +The following sections enumerate the public variables provided by +standard tapsets installed under @prefix@/share/systemtap/tapset. Each +variable is described with a type, and its behavior/restrictions. +The syntax is the same as printed with the +.IR stap " option " \-p2 . +Examples: + +.TP +example1:long +Variable "example1" contains an integer. + +.TP +example2:string [long] +Variable "example2" is an array of strings, indexed by integers. + +.SS ARGV + +.TP +argc:long +Contains the value of the +.BR +$# +value: the number of command line arguments passed to the systemtap script. +It is initialized with an implicit begin(-1) probe. + +.TP +argv:string [long] +Contains each command line argument as a string. argv[1] will equal @1 if +there was at least one command line argument. Arguments beyond #32 are not +transcribed, and produce a warning message within the begin(-1) probe that +initializes this array. + +.SS NULL + +.TP +NULL:long +Simply defined as the number 0. + +.SH FILES +.nh +.IR @prefix@/share/systemtap/tapset +.hy + +.SH SEE ALSO +.IR stap (1) diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 4b37471c..7365d4c9 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,90 @@ +2008-06-23 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp: Add sys_mknodat. + +2008-06-20 wcohen <wcohen@redhat.com> + + * dev.stp: New. + +2008-06-19 Zhaolei <zhaolei@cn.fujitsu.com> + + * aux_syscalls.stp: Output unknown bits in _stp_lookup_or_str. + +2008-06-17 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp: Add sys_linkat. + +2008-06-17 Zhaolei <zhaolei@cn.fujitsu.com> + + * aux_syscalls.stp (__fork_flags): Add termination signal. + +2008-06-13 Josh Stone <joshua.i.stone@intel.com> + + * aux_syscalls.stp, ctime.stp, inet.stp, memory.stp, + s390x/syscalls.stp, {i686,x86_64,ppc64}/registers.stp: Add + 'pure' to embedded-C functions that deserve it. + +2008-06-13 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp: Add sys_fchownat. + +2008-06-12 Will Cohen <wcohen@redhat.com> + + * tasks.stp: Add user_mode. + +2008-06-11 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp: Add sys_fchmodat. + +2008-06-10 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp: Add sys_faccessat. + +2008-06-10 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls.stp(syscall.mkdirat): Use _dfd_str() to add support + for AT_FDCWD. + +2008-06-10 Frank Ch. Eigler <fche@elastic.org> + + PR 6470. + * argv.stp: New tapset. + +2008-06-09 David Smith <dsmith@redhat.com> + + * x86_64/registers.stp (syscall_nr): Added syscall_nr function. + * i686/registers.stp (syscall_nr): Ditto. + +2008-06-04 Zhaolei <zhaolei@cn.fujitsu.com> + + * syscalls2.stp: Add sys_unshare. + +2008-06-03 Zhaolei <zhaolei@cn.fujitsu.com> + + * aux_syscalls.stp (__fork_flags): Support for new clone flags + before linux-2.6.25. + +2008-05-26 Mark Wielaard <mwielaard@redhat.com> + + * task.stp : Only include fdtable.h for kernel versions > 2.6.25. + +2008-05-26 Wenji Huang <wenji.huang@oracle.com> + + * task.stp : Include fdtable.h for 2.6.26. + +2008-05-26 Wenji Huang <wenji.huang@oracle.com> + + * signal.stp (send.*): Correct for 2.6.26. + +2008-05-23 Frank Ch. Eigler <fche@elastic.org> + + * nfs.stp (*): Similarly convert kernel?,module? -> kernel!,module. + +2008-05-23 Frank Ch. Eigler <fche@elastic.org> + + * rpc.stp (*): Convert kernel?,module? -> kernel!,module probe points. + (rpc_create_task): Make conditional on kernel <= 2.6.18. + 2008-05-21 Frank Ch. Eigler <fche@elastic.org> PR 6538 diff --git a/tapset/argv.stp b/tapset/argv.stp new file mode 100644 index 00000000..c941bfc5 --- /dev/null +++ b/tapset/argv.stp @@ -0,0 +1,48 @@ +// argument vector tapset +// 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. + + +global argc = $# +global argv %( $# >= 1 %? [$#] %: [1] %) + +probe begin(-1) { + %( $# == 0 %? argv[0] = "nothing"; delete argv[0] %) # ensure argv is set sometime + %( $# >= 1 %? argv[1]=@1 %) + %( $# >= 2 %? argv[2]=@2 %) + %( $# >= 3 %? argv[3]=@3 %) + %( $# >= 4 %? argv[4]=@4 %) + %( $# >= 5 %? argv[5]=@5 %) + %( $# >= 6 %? argv[6]=@6 %) + %( $# >= 7 %? argv[7]=@7 %) + %( $# >= 8 %? argv[8]=@8 %) + %( $# >= 9 %? argv[9]=@9 %) + %( $# >= 10 %? argv[10]=@10 %) + %( $# >= 11 %? argv[11]=@11 %) + %( $# >= 12 %? argv[12]=@12 %) + %( $# >= 13 %? argv[13]=@13 %) + %( $# >= 14 %? argv[14]=@14 %) + %( $# >= 15 %? argv[15]=@15 %) + %( $# >= 16 %? argv[16]=@16 %) + %( $# >= 17 %? argv[17]=@17 %) + %( $# >= 18 %? argv[18]=@18 %) + %( $# >= 19 %? argv[19]=@19 %) + %( $# >= 20 %? argv[20]=@20 %) + %( $# >= 21 %? argv[21]=@21 %) + %( $# >= 22 %? argv[22]=@22 %) + %( $# >= 23 %? argv[23]=@23 %) + %( $# >= 24 %? argv[24]=@24 %) + %( $# >= 25 %? argv[25]=@25 %) + %( $# >= 26 %? argv[26]=@26 %) + %( $# >= 27 %? argv[27]=@27 %) + %( $# >= 28 %? argv[28]=@28 %) + %( $# >= 29 %? argv[29]=@29 %) + %( $# >= 30 %? argv[30]=@30 %) + %( $# >= 31 %? argv[31]=@31 %) + %( $# >= 32 %? argv[32]=@32 %) + %( $# >= 33 %? warn(sprintf("argv is limited to 32 arguments")) %) +} diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp index ec7fdcb0..f79acaf0 100644 --- a/tapset/aux_syscalls.stp +++ b/tapset/aux_syscalls.stp @@ -1548,7 +1548,7 @@ void _stp_lookup_str(const _stp_val_array * const array, long val, char *ptr, in } void _stp_lookup_or_str(const _stp_val_array * const array, long val, char *ptr, int len) { - int i = 0, flag = 0; + int i = 0, flag = 0, slen; if (val == 0) { _stp_lookup_str(array, val, ptr, len); @@ -1560,12 +1560,15 @@ void _stp_lookup_or_str(const _stp_val_array * const array, long val, char *ptr, if (flag) strlcat(ptr, "|", len); strlcat(ptr, array[i].name, len); + val &= (~array[i].val); flag = 1; } i++; } - if (flag == 0) { - int slen = strlen(ptr); + if (val) { + if (flag) + strlcat(ptr, "|", len); + slen = strlen(ptr); _stp_snprintf(ptr + slen, len - slen, "0x%lx", val); } } @@ -1686,18 +1689,32 @@ const _stp_val_array const _stp_fork_list[] = { V(CLONE_CHILD_SETTID), V(CLONE_STOPPED), #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) + V(CLONE_NEWUTS), V(CLONE_NEWIPC), #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) V(CLONE_NEWUSER), #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + V(CLONE_NEWPID), + V(CLONE_NEWNET), +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) + V(CLONE_IO), +#endif {0, NULL} }; %} function __fork_flags:string(flags:long) %{ /* pure */ - _stp_lookup_or_str(_stp_fork_list, THIS->flags, THIS->__retvalue, MAXSTRINGLEN); + _stp_lookup_or_str(_stp_fork_list, THIS->flags & ~0xff, THIS->__retvalue, MAXSTRINGLEN); + if ( THIS->flags & 0xff ) { + /* flags contains the termination signal */ + if (*THIS->__retvalue) + strlcat(THIS->__retvalue, "|", MAXSTRINGLEN); + _stp_lookup_str(_stp_signal_list, THIS->flags & 0xff, THIS->__retvalue, MAXSTRINGLEN); + } %} %{ @@ -1779,7 +1796,7 @@ function _mmap_flags:string(flags:long) # old mmap functions passed in a struct like this. # function get_mmap_args:string (args:long) -%{ +%{ /* pure */ #if defined (__x86_64__) || defined (__ia64__) struct mmap_arg_struct { unsigned int addr; diff --git a/tapset/context.stp b/tapset/context.stp index dc560316..10c52226 100644 --- a/tapset/context.stp +++ b/tapset/context.stp @@ -136,6 +136,22 @@ function probemod:string () %{ /* pure */ } %} +function registers_valid:long () %{ /* pure */ + THIS->__retvalue = (CONTEXT->regs != NULL); +%} + +function user_mode:long () %{ /* pure */ /* currently a user-mode address? */ + if (CONTEXT->regs) { +#if defined(__i386__) || defined(__x86_64__) + THIS->__retvalue = (uint64_t) user_mode_vm (CONTEXT->regs); +#else + THIS->__retvalue = (uint64_t) user_mode (CONTEXT->regs); +#endif + } else { + THIS->__retvalue = 0; + } +%} + function is_return:long () %{ /* pure */ if (CONTEXT->pi) THIS->__retvalue = 1; diff --git a/tapset/ctime.stp b/tapset/ctime.stp index 96af4d47..d907c2db 100644 --- a/tapset/ctime.stp +++ b/tapset/ctime.stp @@ -41,7 +41,7 @@ */ function ctime:string(epochsecs:long) -%{ +%{ /* pure */ #define SECSPERMIN 60L #define MINSPERHOUR 60L diff --git a/tapset/dev.stp b/tapset/dev.stp new file mode 100644 index 00000000..80449324 --- /dev/null +++ b/tapset/dev.stp @@ -0,0 +1,33 @@ +// Device numbering tapset +// Copyright (C) 2008 Red Hat 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/kdev_t.h> +%} + +function MAJOR:long(dev:long) +%{ /* pure */ + THIS->__retvalue = MAJOR(THIS->dev); +%} + + +function MINOR:long(dev:long) +%{ /* pure */ + THIS->__retvalue = MINOR(THIS->dev); +%} + + +function MKDEV:long(major:long, minor:long) +%{ /* pure */ + THIS->__retvalue = MKDEV(THIS->major,THIS->minor); +%} + +function usrdev2kerndev:long(dev:long) +%{ /* pure */ + THIS->__retvalue = new_decode_dev(THIS->dev); +%} diff --git a/tapset/i686/registers.stp b/tapset/i686/registers.stp index db532f7a..c4c84814 100644 --- a/tapset/i686/registers.stp +++ b/tapset/i686/registers.stp @@ -1,4 +1,4 @@ -global _reg_offsets, _stp_regs_registered +global _reg_offsets, _stp_regs_registered, _sp_offset, _ss_offset function _stp_register_regs() { /* Same order as pt_regs */ @@ -16,19 +16,21 @@ function _stp_register_regs() { _reg_offsets["eip"] = 44 _reg_offsets["ip"] = 44 _reg_offsets["xcs"] = 48 _reg_offsets["cs"] = 48 _reg_offsets["eflags"] = 52 _reg_offsets["flags"] = 52 - _reg_offsets["esp"] = 56 _reg_offsets["sp"] = 56 sp_offset = 56 - _reg_offsets["xss"] = 60 _reg_offsets["ss"] = 60 ss_offset = 60 + _reg_offsets["esp"] = 56 _reg_offsets["sp"] = 56 + _reg_offsets["xss"] = 60 _reg_offsets["ss"] = 60 + _sp_offset = 56 + _ss_offset = 60 _stp_regs_registered = 1 } -function _stp_get_register_by_offset:long (offset:long) %{ +function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; %} -function _stp_probing_kernel:long () %{ +function _stp_probing_kernel:long () %{ /* pure */ THIS->__retvalue = !user_mode(CONTEXT->regs); %} @@ -36,12 +38,12 @@ function _stp_probing_kernel:long () %{ * esp and ss aren't saved on a breakpoint in kernel mode, so * the pre-trap stack pointer is ®s->sp. */ -function _stp_kernel_sp:long (sp_offset:long) %{ +function _stp_kernel_sp:long (sp_offset:long) %{ /* pure */ THIS->__retvalue = ((long) CONTEXT->regs) + THIS->sp_offset; %} /* Assume ss register hasn't changed since we took the trap. */ -function _stp_kernel_ss:long () %{ +function _stp_kernel_ss:long () %{ /* pure */ unsigned short ss; asm volatile("movw %%ss, %0" : : "m" (ss)); THIS->__retvalue = ss; @@ -49,6 +51,10 @@ function _stp_kernel_ss:long () %{ /* Return the named register value as a signed value. */ function register:long (name:string) { + if (!registers_valid()) { + error("cannot access CPU registers in this context") + return 0 + } if (!_stp_regs_registered) _stp_register_regs() offset = _reg_offsets[name] @@ -57,9 +63,9 @@ function register:long (name:string) { return 0 } if (_stp_probing_kernel()) { - if (offset == sp_offset) - return _stp_kernel_sp(sp_offset) - else if (offset == ss_offset) + if (offset == _sp_offset) + return _stp_kernel_sp(_sp_offset) + else if (offset == _ss_offset) return _stp_kernel_ss() } return _stp_get_register_by_offset(offset) @@ -74,7 +80,7 @@ function u_register:long (name:string) { } /* Return the value of function arg #argnum (1=first arg) as a signed value. */ -function _stp_arg:long (argnum:long) %{ +function _stp_arg:long (argnum:long) %{ /* pure */ long val; int n, nr_regargs, result; @@ -192,11 +198,15 @@ function fastcall() %{ CONTEXT->regparm = _STP_REGPARM | 3; %} -function regparm(n) %{ +function regparm(n:long) %{ if (THIS->n < 0 || THIS->n > 3) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "For i386, regparm value must be in the range 0-3."); CONTEXT->last_error = CONTEXT->error_buffer; } else - CONTEXT->regparm = _STP_REGPARM | (int) n; + CONTEXT->regparm = _STP_REGPARM | (int) THIS->n; %} + +function syscall_nr:long() { + return register("orig_ax") +} diff --git a/tapset/inet.stp b/tapset/inet.stp index 0fdd4bab..8681fa2c 100644 --- a/tapset/inet.stp +++ b/tapset/inet.stp @@ -1,8 +1,8 @@ /* Some functions from libc <arpa/inet.h> */ -function htonll:long (x:long) %{ THIS->__retvalue = (int64_t) cpu_to_be64 ((u64) THIS->x); %} -function htonl:long (x:long) %{ THIS->__retvalue = (int64_t) cpu_to_be32 ((u32) THIS->x); %} -function htons:long (x:long) %{ THIS->__retvalue = (int64_t) cpu_to_be16 ((u16) THIS->x); %} -function ntohll:long (x:long) %{ THIS->__retvalue = (int64_t) be64_to_cpu ((u64) THIS->x); %} -function ntohl:long (x:long) %{ THIS->__retvalue = (int64_t) be32_to_cpu ((u32) THIS->x); %} -function ntohs:long (x:long) %{ THIS->__retvalue = (int64_t) be16_to_cpu ((u16) THIS->x); %} +function htonll:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) cpu_to_be64 ((u64) THIS->x); %} +function htonl:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) cpu_to_be32 ((u32) THIS->x); %} +function htons:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) cpu_to_be16 ((u16) THIS->x); %} +function ntohll:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) be64_to_cpu ((u64) THIS->x); %} +function ntohl:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) be32_to_cpu ((u32) THIS->x); %} +function ntohs:long (x:long) %{ /* pure */ THIS->__retvalue = (int64_t) be16_to_cpu ((u16) THIS->x); %} diff --git a/tapset/memory.stp b/tapset/memory.stp index 630e8984..a2d9cc19 100644 --- a/tapset/memory.stp +++ b/tapset/memory.stp @@ -46,8 +46,7 @@ probe vm.pagefault.return = kernel.function("__handle_mm_fault@mm/memory.c").ret } /* Return which node the given address belongs to in a NUMA system */ -function addr_to_node:long(addr:long) /* pure */ -%{ +function addr_to_node:long(addr:long) %{ /* pure */ int nid; int pfn = __pa(THIS->addr) >> PAGE_SHIFT; for_each_online_node(nid) diff --git a/tapset/nd_syscalls.stp b/tapset/nd_syscalls.stp index 5697cd21..5a258e75 100644 --- a/tapset/nd_syscalls.stp +++ b/tapset/nd_syscalls.stp @@ -46,7 +46,7 @@ probe nd_syscall.accept = kernel.function("sys_accept") ? { asmlinkage() sockfd = int_arg(1) addr_uaddr = pointer_arg(2) - addrlen_uaddr = int_arg(3) + addrlen_uaddr = pointer_arg(3) argstr = sprintf("%d, %p, %p", sockfd, addr_uaddr, addrlen_uaddr) } probe nd_syscall.accept.return = kernel.function("sys_accept").return ? { diff --git a/tapset/nfs.stp b/tapset/nfs.stp index ba6bde5f..474b091f 100644 --- a/tapset/nfs.stp +++ b/tapset/nfs.stp @@ -305,9 +305,9 @@ probe nfs.fop.entries = nfs.fop.llseek, nfs.fop.open, nfs.fop.flush, nfs.fop.release, + %( kernel_v <= "2.6.18" %? nfs.fop.sendfile, %) nfs.fop.fsync, - nfs.fop.lock, - nfs.fop.sendfile + nfs.fop.lock { } @@ -320,9 +320,9 @@ probe nfs.fop.return = nfs.fop.llseek.return, nfs.fop.open.return, nfs.fop.flush.return, nfs.fop.release.return, + %( kernel_v <= "2.6.18" %? nfs.fop.sendfile.return, %) nfs.fop.fsync.return, - nfs.fop.lock.return, - nfs.fop.sendfile.return + nfs.fop.lock.return { } @@ -344,8 +344,8 @@ probe nfs.fop.return = nfs.fop.llseek.return, * The offset is set to the size of the file plus offset bytes. * */ -probe nfs.fop.llseek = kernel.function ("nfs_file_llseek") ?, - module("nfs").function("nfs_file_llseek") ? +probe nfs.fop.llseek = kernel.function ("nfs_file_llseek") !, + module("nfs").function("nfs_file_llseek") { dev = __file_dev($filp) ino = __file_ino($filp) @@ -360,8 +360,8 @@ probe nfs.fop.llseek = kernel.function ("nfs_file_llseek") ?, argstr = sprintf("%d, %d", offset, origin) } -probe nfs.fop.llseek.return = kernel.function ("nfs_file_llseek").return ?, - module("nfs").function("nfs_file_llseek").return ? +probe nfs.fop.llseek.return = kernel.function ("nfs_file_llseek").return !, + module("nfs").function("nfs_file_llseek").return { name = "nfs.fop.llseek.return" retstr = sprintf("%d", $return) @@ -429,8 +429,8 @@ probe nfs.fop.write.return = vfs.do_sync_write.return * * jiffies - read_cache_jiffies > attrtimeo */ -probe nfs.fop.aio_read = kernel.function ("nfs_file_read") ?, - module("nfs").function("nfs_file_read") ? +probe nfs.fop.aio_read = kernel.function ("nfs_file_read") !, + module("nfs").function("nfs_file_read") { dev = __file_dev($iocb->ki_filp) ino = __file_ino($iocb->ki_filp) @@ -464,8 +464,8 @@ probe nfs.fop.aio_read = kernel.function ("nfs_file_read") ?, } -probe nfs.fop.aio_read.return = kernel.function ("nfs_file_read").return ?, - module("nfs").function("nfs_file_read").return ? +probe nfs.fop.aio_read.return = kernel.function ("nfs_file_read").return !, + module("nfs").function("nfs_file_read").return { name = "nfs.fop.aio_read.return" retstr = sprintf("%d", $return) @@ -490,8 +490,8 @@ probe nfs.fop.aio_read.return = kernel.function ("nfs_file_read").return ?, * file_name : file name * */ -probe nfs.fop.aio_write = kernel.function("nfs_file_write") ?, - module("nfs").function("nfs_file_write") ? +probe nfs.fop.aio_write = kernel.function("nfs_file_write") !, + module("nfs").function("nfs_file_write") { dev = __file_dev($iocb->ki_filp) ino = __file_ino($iocb->ki_filp) @@ -517,8 +517,8 @@ probe nfs.fop.aio_write = kernel.function("nfs_file_write") ?, units = "bytes" } -probe nfs.fop.aio_write.return = kernel.function("nfs_file_write").return ?, - module("nfs").function("nfs_file_write").return ? +probe nfs.fop.aio_write.return = kernel.function("nfs_file_write").return !, + module("nfs").function("nfs_file_write").return { name = "nfs.fop.aio_write.return" retstr = sprintf("%d", $return) @@ -551,8 +551,8 @@ probe nfs.fop.aio_write.return = kernel.function("nfs_file_write").return ?, * * jiffies - read_cache_jiffies > attrtimeo */ -probe nfs.fop.mmap = kernel.function("nfs_file_mmap") ?, - module("nfs").function("nfs_file_mmap") ? +probe nfs.fop.mmap = kernel.function("nfs_file_mmap") !, + module("nfs").function("nfs_file_mmap") { dev = __file_dev($file) ino = __file_ino($file) @@ -574,8 +574,8 @@ probe nfs.fop.mmap = kernel.function("nfs_file_mmap") ?, argstr = sprintf("0x%x, 0x%x, 0x%x", vm_start, vm_end, vm_flags) } -probe nfs.fop.mmap.return = kernel.function("nfs_file_mmap").return ?, - module("nfs").function("nfs_file_mmap").return ? +probe nfs.fop.mmap.return = kernel.function("nfs_file_mmap").return !, + module("nfs").function("nfs_file_mmap").return { name = "nfs.fop.mmap.return" retstr = sprintf("%d", $return) @@ -593,8 +593,8 @@ probe nfs.fop.mmap.return = kernel.function("nfs_file_mmap").return ?, * flag : file flag * i_size : file length in bytes */ -probe nfs.fop.open = kernel.function("nfs_file_open") ?, - module("nfs").function("nfs_file_open") ? +probe nfs.fop.open = kernel.function("nfs_file_open") !, + module("nfs").function("nfs_file_open") { dev = __file_dev($filp) ino = $inode->i_ino @@ -610,8 +610,8 @@ probe nfs.fop.open = kernel.function("nfs_file_open") ?, argstr = sprintf("%d,%d, %s", flag, ino, filename) } -probe nfs.fop.open.return = kernel.function("nfs_file_open").return ?, - module("nfs").function("nfs_file_open").return ? +probe nfs.fop.open.return = kernel.function("nfs_file_open").return !, + module("nfs").function("nfs_file_open").return { name = "nfs.fop.open.return" retstr = sprintf("%d", $return) @@ -628,8 +628,8 @@ probe nfs.fop.open.return = kernel.function("nfs_file_open").return ?, * mode : file mode * ndirty : number of dirty page */ -probe nfs.fop.flush = kernel.function("nfs_file_flush") ?, - module("nfs").function("nfs_file_flush") ? +probe nfs.fop.flush = kernel.function("nfs_file_flush") !, + module("nfs").function("nfs_file_flush") { dev = __file_dev($file) ino = __file_ino($file) @@ -643,8 +643,8 @@ probe nfs.fop.flush = kernel.function("nfs_file_flush") ?, argstr = sprintf("%d",ino) } -probe nfs.fop.flush.return = kernel.function("nfs_file_flush").return ?, - module("nfs").function("nfs_file_flush").return ? +probe nfs.fop.flush.return = kernel.function("nfs_file_flush").return !, + module("nfs").function("nfs_file_flush").return { name = "nfs.fop.flush.return" retstr = sprintf("%d",$return) @@ -660,8 +660,8 @@ probe nfs.fop.flush.return = kernel.function("nfs_file_flush").return ?, * ino : inode number * mode : file mode */ -probe nfs.fop.release = kernel.function("nfs_file_release") ?, - module("nfs").function("nfs_file_release") ? +probe nfs.fop.release = kernel.function("nfs_file_release") !, + module("nfs").function("nfs_file_release") { dev = __file_dev($filp) ino = $inode->i_ino @@ -674,8 +674,8 @@ probe nfs.fop.release = kernel.function("nfs_file_release") ?, argstr = sprintf("%d" , ino) } -probe nfs.fop.release.return = kernel.function("nfs_file_release").return ?, - module("nfs").function("nfs_file_release").return ? +probe nfs.fop.release.return = kernel.function("nfs_file_release").return !, + module("nfs").function("nfs_file_release").return { name = "nfs.fop.release.return" retstr = sprintf("%d", $return) @@ -691,8 +691,8 @@ probe nfs.fop.release.return = kernel.function("nfs_file_release").return ?, * ino : inode number * ndirty : number of dirty pages */ -probe nfs.fop.fsync = kernel.function("nfs_fsync") ?, - module("nfs").function("nfs_fsync") ? +probe nfs.fop.fsync = kernel.function("nfs_fsync") !, + module("nfs").function("nfs_fsync") { dev = __file_dev($file) ino = __file_ino($file) @@ -705,8 +705,8 @@ probe nfs.fop.fsync = kernel.function("nfs_fsync") ?, argstr = sprintf("%d",ino) } -probe nfs.fop.fsync.return = kernel.function("nfs_fsync").return ?, - module("nfs").function("nfs_fsync").return ? +probe nfs.fop.fsync.return = kernel.function("nfs_fsync").return !, + module("nfs").function("nfs_fsync").return { name = "nfs.fop.fsync.return" retstr = sprintf("%d", $return) @@ -727,8 +727,8 @@ probe nfs.fop.fsync.return = kernel.function("nfs_fsync").return ?, * fl_start : starting offset of locked region * fl_end : ending offset of locked region */ -probe nfs.fop.lock = kernel.function("nfs_lock") ?, - module("nfs").function("nfs_lock") ? +probe nfs.fop.lock = kernel.function("nfs_lock") !, + module("nfs").function("nfs_lock") { dev = __file_dev($filp) ino = __file_ino($filp) @@ -747,8 +747,8 @@ probe nfs.fop.lock = kernel.function("nfs_lock") ?, argstr = sprintf("%d,%d",cmd,i_mode) } -probe nfs.fop.lock.return = kernel.function("nfs_lock").return ?, - module("nfs").function("nfs_lock").return ? +probe nfs.fop.lock.return = kernel.function("nfs_lock").return !, + module("nfs").function("nfs_lock").return { name = "nfs.fop.lock.return" retstr = sprintf("%d",$return) @@ -773,8 +773,9 @@ probe nfs.fop.lock.return = kernel.function("nfs_lock").return ?, * * jiffies - read_cache_jiffies > attrtimeo */ -probe nfs.fop.sendfile = kernel.function("nfs_file_sendfile") ?, - module("nfs").function("nfs_file_sendfile") ? +%( kernel_v <= "2.6.18" %? +probe nfs.fop.sendfile = kernel.function("nfs_file_sendfile") !, + module("nfs").function("nfs_file_sendfile") { dev = __file_dev($filp) @@ -796,8 +797,8 @@ probe nfs.fop.sendfile = kernel.function("nfs_file_sendfile") ?, units = "bytes" } -probe nfs.fop.sendfile.return = kernel.function("nfs_file_sendfile").return ?, - module("nfs").function("nfs_file_sendfile").return ? +probe nfs.fop.sendfile.return = kernel.function("nfs_file_sendfile").return !, + module("nfs").function("nfs_file_sendfile").return { name = "nfs.fop.sendfile.return" retstr = sprintf("%d", $return) @@ -807,6 +808,7 @@ probe nfs.fop.sendfile.return = kernel.function("nfs_file_sendfile").return ?, units = "bytes" } } +%) /*probe nfs.fop.check_flags * @@ -816,8 +818,8 @@ probe nfs.fop.sendfile.return = kernel.function("nfs_file_sendfile").return ?, * Arguments: * flag : file flag */ -probe nfs.fop.check_flags = kernel.function("nfs_check_flags") ?, - module("nfs").function("nfs_check_flags") ? +probe nfs.fop.check_flags = kernel.function("nfs_check_flags") !, + module("nfs").function("nfs_check_flags") { flag = $flags @@ -825,8 +827,8 @@ probe nfs.fop.check_flags = kernel.function("nfs_check_flags") ?, argstr = sprintf("%d",flag) } -probe nfs.fop.check_flags.return = kernel.function("nfs_check_flags").return ?, - module("nfs").function("nfs_check_flags").return ? +probe nfs.fop.check_flags.return = kernel.function("nfs_check_flags").return !, + module("nfs").function("nfs_check_flags").return { name = "nfs.fop.check_flags.return" retstr = sprintf("%d",$return) @@ -871,8 +873,8 @@ probe nfs.aop.return = nfs.aop.readpage.return, * rsize : read size (in bytes) * size : number of pages to be read in this execution */ -probe nfs.aop.readpage = kernel.function ("nfs_readpage") ?, - module("nfs").function ("nfs_readpage") ? +probe nfs.aop.readpage = kernel.function ("nfs_readpage") !, + module("nfs").function ("nfs_readpage") { __page = $page dev = __page_dev(__page) @@ -896,8 +898,8 @@ probe nfs.aop.readpage = kernel.function ("nfs_readpage") ?, units = "pages" } -probe nfs.aop.readpage.return = kernel.function ("nfs_readpage").return ?, - module("nfs").function ("nfs_readpage").return ? +probe nfs.aop.readpage.return = kernel.function ("nfs_readpage").return !, + module("nfs").function ("nfs_readpage").return { name = "nfs.aop.readpage.return" retstr = sprintf("%d", $return) @@ -918,8 +920,8 @@ probe nfs.aop.readpage.return = kernel.function ("nfs_readpage").return ?, * rsize : read size (in bytes) * size : number of pages attempted to read in this execution */ -probe nfs.aop.readpages = kernel.function ("nfs_readpages") ?, - module("nfs").function ("nfs_readpages") ? +probe nfs.aop.readpages = kernel.function ("nfs_readpages") !, + module("nfs").function ("nfs_readpages") { dev = $mapping->host->i_sb->s_dev ino = $mapping->host->i_ino @@ -937,8 +939,8 @@ probe nfs.aop.readpages = kernel.function ("nfs_readpages") ?, units = "pages" } -probe nfs.aop.readpages.return = kernel.function ("nfs_readpages").return ?, - module("nfs").function ("nfs_readpages").return ? +probe nfs.aop.readpages.return = kernel.function ("nfs_readpages").return !, + module("nfs").function ("nfs_readpages").return { name = "nfs.aop.readpages.return" retstr = sprintf("%d", $return) @@ -960,8 +962,8 @@ probe nfs.aop.readpages.return = kernel.function ("nfs_readpages").return ?, * page_flag : page flags */ probe nfs.aop.set_page_dirty = - kernel.function ("__set_page_dirty_nobuffers") ?, - module("nfs").function ("__set_page_dirty_nobuffers") ? + kernel.function ("__set_page_dirty_nobuffers") !, + module("nfs").function ("__set_page_dirty_nobuffers") { /* dev = $mapping->host->i_sb->s_dev devname = __find_bdevname(dev, $mapping->host->i_sb->s_bdev) @@ -975,8 +977,8 @@ probe nfs.aop.set_page_dirty = } probe nfs.aop.set_page_dirty.return = - kernel.function ("__set_page_dirty_nobuffers") .return?, - module("nfs").function ("__set_page_dirty_nobuffers").return ? + kernel.function ("__set_page_dirty_nobuffers") .return !, + module("nfs").function ("__set_page_dirty_nobuffers").return { name = "nfs.aop.set_page_dirty.return" retstr = sprintf("%d", $return) @@ -1003,8 +1005,8 @@ probe nfs.aop.set_page_dirty.return = * wsize : write size * size : number of pages to be written in this execution */ -probe nfs.aop.writepage = kernel.function ("nfs_writepage") ?, - module("nfs").function ("nfs_writepage") ? +probe nfs.aop.writepage = kernel.function ("nfs_writepage") !, + module("nfs").function ("nfs_writepage") { __page = $page dev = __page_dev(__page) @@ -1033,8 +1035,8 @@ probe nfs.aop.writepage = kernel.function ("nfs_writepage") ?, units = "pages" } -probe nfs.aop.writepage.return = kernel.function ("nfs_writepage").return ?, - module("nfs").function ("nfs_writepage").return ? +probe nfs.aop.writepage.return = kernel.function ("nfs_writepage").return !, + module("nfs").function ("nfs_writepage").return { name = "nfs.aop.writepage.return" retstr = sprintf("%d", $return) @@ -1053,8 +1055,8 @@ probe nfs.aop.writepage.return = kernel.function ("nfs_writepage").return ?, * nr_to_write : number of pages attempted to be written in this execution * size : number of pages attempted to be written in this execution */ -probe nfs.aop.writepages = kernel.function ("nfs_writepages") ?, - module("nfs").function ("nfs_writepages") ? +probe nfs.aop.writepages = kernel.function ("nfs_writepages") !, + module("nfs").function ("nfs_writepages") { dev = $mapping->host->i_sb->s_dev ino = $mapping->host->i_ino @@ -1073,8 +1075,8 @@ probe nfs.aop.writepages = kernel.function ("nfs_writepages") ?, units = "pages" } -probe nfs.aop.writepages.return = kernel.function ("nfs_writepages").return ?, - module("nfs").function ("nfs_writepages").return ? +probe nfs.aop.writepages.return = kernel.function ("nfs_writepages").return !, + module("nfs").function ("nfs_writepages").return { name = "nfs.aop.writepages.return" retstr = sprintf("%d", $return) @@ -1099,8 +1101,8 @@ probe nfs.aop.writepages.return = kernel.function ("nfs_writepages").return ?, in the page frame * size : write bytes */ -probe nfs.aop.prepare_write= kernel.function ("nfs_prepare_write") ?, - module("nfs").function ("nfs_prepare_write") ? +probe nfs.aop.prepare_write= kernel.function ("nfs_prepare_write") !, + module("nfs").function ("nfs_prepare_write") { __page = $page dev = __page_dev(__page) @@ -1120,8 +1122,8 @@ probe nfs.aop.prepare_write= kernel.function ("nfs_prepare_write") ?, } probe nfs.aop.prepare_write.return = - kernel.function ("nfs_prepare_write").return ?, - module("nfs").function ("nfs_prepare_write").return ? + kernel.function ("nfs_prepare_write").return !, + module("nfs").function ("nfs_prepare_write").return { name = "nfs.aop.prepare_write.return" retstr = sprintf("%d", $return) @@ -1147,8 +1149,8 @@ probe nfs.aop.prepare_write.return = in the page frame * size : write bytes */ -probe nfs.aop.commit_write= kernel.function ("nfs_commit_write") ?, - module("nfs").function ("nfs_commit_write") ? +probe nfs.aop.commit_write= kernel.function ("nfs_commit_write") !, + module("nfs").function ("nfs_commit_write") { __page = $page dev = __page_dev(__page) @@ -1174,8 +1176,8 @@ probe nfs.aop.commit_write= kernel.function ("nfs_commit_write") ?, probe nfs.aop.commit_write.return= - kernel.function ("nfs_commit_write").return ?, - module("nfs").function ("nfs_commit_write").return? + kernel.function ("nfs_commit_write").return !, + module("nfs").function ("nfs_commit_write").return { name = "nfs.aop.commit_write.return" retstr = sprintf("%d", $return) @@ -1194,8 +1196,8 @@ probe nfs.aop.commit_write.return= in the page frame * size : release pages */ -probe nfs.aop.release_page = kernel.function ("nfs_release_page") ?, - module("nfs").function ("nfs_release_page")? +probe nfs.aop.release_page = kernel.function ("nfs_release_page") !, + module("nfs").function ("nfs_release_page") { __page = $page dev = __page_dev(__page) @@ -1212,8 +1214,8 @@ probe nfs.aop.release_page = kernel.function ("nfs_release_page") ?, } -probe nfs.aop.release_page.return = kernel.function ("nfs_release_page").return ?, - module("nfs").function ("nfs_release_page").return? +probe nfs.aop.release_page.return = kernel.function ("nfs_release_page").return !, + module("nfs").function ("nfs_release_page").return { name = "nfs.aop.release_page.return" retstr = sprintf("%d", $return) diff --git a/tapset/nfs_proc.stp b/tapset/nfs_proc.stp index 2dc7e659..6ffdf646 100644 --- a/tapset/nfs_proc.stp +++ b/tapset/nfs_proc.stp @@ -559,6 +559,9 @@ probe nfs.proc.commit.return = nfs.proc3.commit.return, nfs.proc4.commit.return {} +// XXX: on kernels > 2.6.18 (?), module("nfs") -> module("nfsd") and +// function("nfsN...") becomes function("nfsdN..."). PR3833. + probe nfs.proc3.commit = kernel.function ("nfs3_proc_commit")?, module("nfs").function("nfs3_proc_commit")? { diff --git a/tapset/ppc64/registers.stp b/tapset/ppc64/registers.stp index d3605c05..6a8ae279 100644 --- a/tapset/ppc64/registers.stp +++ b/tapset/ppc64/registers.stp @@ -58,7 +58,11 @@ function _stp_register_regs() { _stp_regs_registered = 1 } -function _stp_get_register_by_offset:long (offset:long) %{ +function probing_32bit_app() %{ /* pure */ + THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); +%} + +function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; @@ -70,14 +74,11 @@ function _stp_sign_extend32:long (value:long) { return value } -function _stp_probing_32bit_app() %{ - if (!(CONTEXT->regs)) - return 0; - return (user_mode(CONTEXT->regs) && - test_tsk_thread_flag(current, TIF_32BIT)); -%} - function _stp_register:long (name:string, sign_extend:long) { + if (!registers_valid()) { + error("cannot access CPU registers in this context") + return 0 + } if (!_stp_regs_registered) _stp_register_regs() offset = _reg_offsets[name] @@ -86,7 +87,7 @@ function _stp_register:long (name:string, sign_extend:long) { return 0 } value = _stp_get_register_by_offset(offset) - if (_stp_probing_32bit_app()) { + if (probing_32bit_app()) { if (sign_extend) value = _stp_sign_extend32(value) else @@ -114,66 +115,39 @@ function u_register:long (name:string) { * If sign_extend=1 and (truncate=1 or the probepoint we've hit is in a * 32-bit app), sign-extend the 32-bit value. */ -function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ - long val; - int n; - size_t argsz = sizeof(long); - - THIS->__retvalue = 0; - if (!CONTEXT->regs) { - snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "cannot access function args in this context"); - CONTEXT->last_error = CONTEXT->error_buffer; - return; - } - if (THIS->argnum < 1) - goto bad_argnum; - n = (int) THIS->argnum; - - switch (n) { - case 1: - val = u_register("r3"); - break; - case 2: - val = u_register("r4"); - break; - case 3: - val = u_register("r5"); - break; - case 4: - val = u_register("r6"); - break; - case 5: - val = u_register("r7"); - break; - case 6: - val = u_register("r8"); - break; - case 7: - val = u_register("r9"); - break; - case 8: - val = u_register("r10"); - break; - default: - goto bad_argnum; +function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) { + val = 0 + if (argnum < 1 || argnum > 8) { + error(sprintf("Cannot access arg(%d)", argnum)) + return 0 } - if (THIS->truncate || argsz == sizeof(int)) { - if (THIS->sign_extend) - THIS->__retvalue = (int64_t) _stp_sign_extend32(val); + + if (argnum == 1) + val = u_register("r3") + else if (argnum == 2) + val = u_register("r4") + else if (argnum == 3) + val = u_register("r5") + else if (argnum == 4) + val = u_register("r6") + else if (argnum == 5) + val = u_register("r7") + else if (argnum == 6) + val = u_register("r8") + else if (argnum == 7) + val = u_register("r9") + else (argnum == 8) + val = u_register("r10") + + if (truncate) { + if (sign_extend) + val = _stp_sign_extend32(val) else /* High bits may be garbage. */ - THIS->__retvalue = (int64_t) (val & 0xffffffff); - } else - THIS->__retvalue = (int64_t) val; - return; - -bad_argnum: - snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), - "cannot access arg(%lld)", THIS->argnum); - CONTEXT->last_error = CONTEXT->error_buffer; - return; -%} + val = (val & 0xffffffff); + } + return val; +} /* Return the value of function arg #argnum (1=first arg) as a signed int. */ function int_arg:long (argnum:long) { @@ -194,7 +168,7 @@ function ulong_arg:long (argnum:long) { } function longlong_arg:long (argnum:long) { - if (_stp_probing_32bit_app()) { + if (probing_32bit_app()) { lowbits = _stp_arg(argnum, 0, 1) highbits = _stp_arg(argnum+1, 0, 1) return ((highbits << 32) | lowbits) diff --git a/tapset/rpc.stp b/tapset/rpc.stp index 537bf348..f97117b5 100644 --- a/tapset/rpc.stp +++ b/tapset/rpc.stp @@ -1,6 +1,7 @@ // rpc tapset // Copyright (C) 2006 IBM Corp. // Copyright (C) 2007 Bull S.A.S +// Copyright (C) 2008 Red Hat // // 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 @@ -79,8 +80,9 @@ probe sunrpc.clnt.create_client = _sunrpc.clnt.create_client.* prog, vers, prot, port, authflavor) } -probe _sunrpc.clnt.create_client.part1 = kernel.function("rpc_create_client") ?, - module("sunrpc").function("rpc_create_client") ? +%( kernel_v <= "2.6.18" %? +probe _sunrpc.clnt.create_client.part1 = kernel.function("rpc_create_client") !, + module("sunrpc").function("rpc_create_client") { name = "sunrpc.clnt.create_client" %( kernel_v >= "2.6.10" %? @@ -95,9 +97,10 @@ probe _sunrpc.clnt.create_client.part1 = kernel.function("rpc_create_client") ?, authflavor = $flavor %) } +%) -probe _sunrpc.clnt.create_client.part2 = kernel.function("rpc_new_client") ?, - module("sunrpc").function("rpc_new_client") ? +probe _sunrpc.clnt.create_client.part2 = kernel.function("rpc_new_client") !, + module("sunrpc").function("rpc_new_client") { name = "sunrpc.clnt.new_client" progname = kernel_string($program->name) @@ -106,21 +109,23 @@ probe _sunrpc.clnt.create_client.part2 = kernel.function("rpc_new_client") ?, authflavor = $flavor } -probe sunrpc.clnt.create_client.return = _sunrpc.clnt.create_client.return.* +probe sunrpc.clnt.create_client.return = _sunrpc.clnt.create_client.return.* { retstr = returnstr(2) } +%( kernel_v <= "2.6.18" %? probe _sunrpc.clnt.create_client.return.part1 = - kernel.function("rpc_create_client").return ?, - module("sunrpc").function("rpc_create_client").return ? + kernel.function("rpc_create_client").return !, + module("sunrpc").function("rpc_create_client").return { name = "sunrpc.clnt.create_client.return" } +%) probe _sunrpc.clnt.create_client.return.part2 = - kernel.function("rpc_new_client").return ?, - module("sunrpc").function("rpc_new_client").return ? + kernel.function("rpc_new_client").return !, + module("sunrpc").function("rpc_new_client").return { name = "sunrpc.clnt.new_client.return" } @@ -138,8 +143,8 @@ probe _sunrpc.clnt.create_client.return.part2 = * @port: the port number * @authflavor: the authentication flavor */ -probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") ?, - module("sunrpc").function("rpc_clone_client") ? +probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") !, + module("sunrpc").function("rpc_clone_client") { servername = kernel_string($clnt->cl_server) progname = kernel_string($clnt->cl_protname) @@ -155,8 +160,8 @@ probe sunrpc.clnt.clone_client = kernel.function("rpc_clone_client") ?, } probe sunrpc.clnt.clone_client.return = - kernel.function("rpc_clone_client").return ?, - module("sunrpc").function("rpc_clone_client").return ? + kernel.function("rpc_clone_client").return !, + module("sunrpc").function("rpc_clone_client").return { name = "sunrpc.clnt.clone_client.return" retstr = returnstr(2) @@ -188,8 +193,8 @@ probe sunrpc.clnt.clone_client.return = * @om_rtt: the RPC RTT jiffies * @om_execute: the RPC execution jiffies */ -probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") ?, - module("sunrpc").function("rpc_shutdown_client") ? +probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") !, + module("sunrpc").function("rpc_shutdown_client") { servername = kernel_string($clnt->cl_server) progname = kernel_string($clnt->cl_protname) @@ -220,8 +225,8 @@ probe sunrpc.clnt.shutdown_client = kernel.function("rpc_shutdown_client") ?, } probe sunrpc.clnt.shutdown_client.return = - kernel.function("rpc_shutdown_client").return ?, - module("sunrpc").function("rpc_shutdown_client").return ? + kernel.function("rpc_shutdown_client").return !, + module("sunrpc").function("rpc_shutdown_client").return { name = "sunrpc.clnt.shutdown_client.return" retstr = returnstr(1) @@ -242,8 +247,8 @@ probe sunrpc.clnt.shutdown_client.return = * @vers: the version of new RPC program */ probe sunrpc.clnt.bind_new_program = - kernel.function("rpc_bind_new_program") ?, - module("sunrpc").function("rpc_bind_new_program") ? + kernel.function("rpc_bind_new_program") !, + module("sunrpc").function("rpc_bind_new_program") { servername = kernel_string($old->cl_server) old_progname = kernel_string($old->cl_protname) @@ -259,8 +264,8 @@ probe sunrpc.clnt.bind_new_program = } probe sunrpc.clnt.bind_new_program.return = - kernel.function("rpc_bind_new_program").return ?, - module("sunrpc").function("rpc_bind_new_program").return ? + kernel.function("rpc_bind_new_program").return !, + module("sunrpc").function("rpc_bind_new_program").return { name = "sunrpc.clnt.bind_new_program.return" retstr = returnstr(2) @@ -282,8 +287,8 @@ probe sunrpc.clnt.bind_new_program.return = * @proc: the procedure number in this RPC call * @flags: flags */ -probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") ?, - module("sunrpc").function("rpc_call_sync") ? +probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") !, + module("sunrpc").function("rpc_call_sync") { servername = kernel_string($clnt->cl_server) progname = kernel_string($clnt->cl_protname) @@ -306,8 +311,8 @@ probe sunrpc.clnt.call_sync = kernel.function("rpc_call_sync") ?, vers, procname, flags) } -probe sunrpc.clnt.call_sync.return = kernel.function("rpc_call_sync").return ?, - module("sunrpc").function("rpc_call_sync").return ? +probe sunrpc.clnt.call_sync.return = kernel.function("rpc_call_sync").return !, + module("sunrpc").function("rpc_call_sync").return { name = "sunrpc.clnt.call_sync.return" retstr = returnstr(1) @@ -329,8 +334,8 @@ probe sunrpc.clnt.call_sync.return = kernel.function("rpc_call_sync").return ?, * @proc: the procedure number in this RPC call * @flags: flags */ -probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") ?, - module("sunrpc").function("rpc_call_async") ? +probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") !, + module("sunrpc").function("rpc_call_async") { servername = kernel_string($clnt->cl_server) progname = kernel_string($clnt->cl_protname) @@ -354,8 +359,8 @@ probe sunrpc.clnt.call_async = kernel.function("rpc_call_async") ?, } probe sunrpc.clnt.call_async.return = - kernel.function("rpc_call_async").return ?, - module("sunrpc").function("rpc_call_async").return ? + kernel.function("rpc_call_async").return !, + module("sunrpc").function("rpc_call_async").return { name = "sunrpc.clnt.call_async.return" retstr = returnstr(1) @@ -374,8 +379,8 @@ probe sunrpc.clnt.call_async.return = * @tk_priority: the task priority * @tk_runstate: the task run status */ -probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") ?, - module("sunrpc").function("rpc_restart_call") ? +probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") !, + module("sunrpc").function("rpc_restart_call") { servername = kernel_string($task->tk_client->cl_server) prog = prog_from_clnt($task->tk_client) @@ -391,8 +396,8 @@ probe sunrpc.clnt.restart_call = kernel.function("rpc_restart_call") ?, } probe sunrpc.clnt.restart_call.return = - kernel.function("rpc_restart_call").return ?, - module("sunrpc").function("rpc_restart_call").return ? + kernel.function("rpc_restart_call").return !, + module("sunrpc").function("rpc_restart_call").return { name = "sunrpc.clnt.restart_call.return" } @@ -434,8 +439,8 @@ probe sunrpc.svc.return = * @prot: the IP protocol number * @port: the port number */ -probe sunrpc.svc.register = kernel.function("svc_register") ?, - module("sunrpc").function("svc_register") ? +probe sunrpc.svc.register = kernel.function("svc_register") !, + module("sunrpc").function("svc_register") { sv_name = kernel_string($serv->sv_name) progname = kernel_string($serv->sv_program->pg_name) @@ -447,8 +452,8 @@ probe sunrpc.svc.register = kernel.function("svc_register") ?, argstr = sprintf("%s %s %d %d", sv_name, progname, prot, port) } -probe sunrpc.svc.register.return = kernel.function("svc_register").return ?, - module("sunrpc").function("svc_register").return ? +probe sunrpc.svc.register.return = kernel.function("svc_register").return !, + module("sunrpc").function("svc_register").return { name = "sunrpc.svc.register.return" retstr = returnstr(1) @@ -465,8 +470,8 @@ probe sunrpc.svc.register.return = kernel.function("svc_register").return ?, * @pg_nvers: the number of supported versions * @bufsize: the buffer size */ -probe sunrpc.svc.create = kernel.function("svc_create") ?, - module("sunrpc").function("svc_create") ? +probe sunrpc.svc.create = kernel.function("svc_create") !, + module("sunrpc").function("svc_create") { progname = kernel_string($prog->pg_name) prog = $prog->pg_prog @@ -477,8 +482,8 @@ probe sunrpc.svc.create = kernel.function("svc_create") ?, argstr = sprintf("%s %d %d %d", progname, prog, pg_nvers, bufsize) } -probe sunrpc.svc.create.return = kernel.function("svc_create").return ?, - module("sunrpc").function("svc_create").return ? +probe sunrpc.svc.create.return = kernel.function("svc_create").return !, + module("sunrpc").function("svc_create").return { name = "sunrpc.svc.create.return" retstr = returnstr(2) @@ -499,8 +504,8 @@ probe sunrpc.svc.create.return = kernel.function("svc_create").return ?, * @rpcbadfmt: the count of requests dropped for bad formats * @rpcbadauth: the count of requests drooped for authentication failure */ -probe sunrpc.svc.destroy = kernel.function("svc_destroy") ?, - module("sunrpc").function("svc_destroy") ? +probe sunrpc.svc.destroy = kernel.function("svc_destroy") !, + module("sunrpc").function("svc_destroy") { sv_name = kernel_string($serv->sv_name) /* service name */ sv_progname = kernel_string($serv->sv_program->pg_name) @@ -518,8 +523,8 @@ probe sunrpc.svc.destroy = kernel.function("svc_destroy") ?, argstr = sprintf("%s %d %d", sv_name, sv_prog, sv_nrthreads) } -probe sunrpc.svc.destroy.return = kernel.function("svc_destroy").return ?, - module("sunrpc").function("svc_destroy").return ? +probe sunrpc.svc.destroy.return = kernel.function("svc_destroy").return !, + module("sunrpc").function("svc_destroy").return { name = "sunrpc.svc.destroy.return" } @@ -539,8 +544,8 @@ probe sunrpc.svc.destroy.return = kernel.function("svc_destroy").return ?, * @rq_proc: the procedure number in the request * @rq_prot: the IP protocol of the reqeust */ -probe sunrpc.svc.process = kernel.function("svc_process") ?, - module("sunrpc").function("svc_process") ? +probe sunrpc.svc.process = kernel.function("svc_process") !, + module("sunrpc").function("svc_process") { %( kernel_v >= "2.6.19" %? sv_name = kernel_string($rqstp->rq_server->sv_name) /* service name */ @@ -563,8 +568,8 @@ probe sunrpc.svc.process = kernel.function("svc_process") ?, rq_xid, rq_prog, rq_vers, rq_proc) } -probe sunrpc.svc.process.return = kernel.function("svc_process").return ?, - module("sunrpc").function("svc_process").return ? +probe sunrpc.svc.process.return = kernel.function("svc_process").return !, + module("sunrpc").function("svc_process").return { name = "sunrpc.svc.process.return" retstr = returnstr(1) @@ -583,8 +588,8 @@ probe sunrpc.svc.process.return = kernel.function("svc_process").return ?, * @rq_proc: the procedure number in the request * @rq_prot: the IP protocol of the reqeust */ -probe sunrpc.svc.authorise = kernel.function("svc_authorise")?, - module("sunrpc").function("svc_authorise")? +probe sunrpc.svc.authorise = kernel.function("svc_authorise") !, + module("sunrpc").function("svc_authorise") { sv_name = kernel_string($rqstp->rq_server->sv_name) peer_ip = addr_from_rqst($rqstp) @@ -599,8 +604,8 @@ probe sunrpc.svc.authorise = kernel.function("svc_authorise")?, rq_vers, rq_proc, rq_prot) } -probe sunrpc.svc.authorise.return = kernel.function("svc_authorise").return ?, - module("sunrpc").function("svc_authorise").return ? +probe sunrpc.svc.authorise.return = kernel.function("svc_authorise").return !, + module("sunrpc").function("svc_authorise").return { name = "sunrpc.svc.authorise.return" retstr = returnstr(1) @@ -616,8 +621,8 @@ probe sunrpc.svc.authorise.return = kernel.function("svc_authorise").return ?, * @sv_nrthreads:the number of concurrent threads * @timeout: the timeout of waiting for data */ -probe sunrpc.svc.recv = kernel.function("svc_recv")?, - module("sunrpc").function("svc_recv")? +probe sunrpc.svc.recv = kernel.function("svc_recv") !, + module("sunrpc").function("svc_recv") { %( kernel_v >= "2.6.19" %? sv_name = kernel_string($rqstp->rq_server->sv_name) @@ -634,8 +639,8 @@ probe sunrpc.svc.recv = kernel.function("svc_recv")?, argstr = sprintf("%s %d", sv_name, timeout) } -probe sunrpc.svc.recv.return = kernel.function("svc_recv").return ?, - module("sunrpc").function("svc_recv").return ? +probe sunrpc.svc.recv.return = kernel.function("svc_recv").return !, + module("sunrpc").function("svc_recv").return { name = "sunrpc.svc.recv.return" retstr = returnstr(1) @@ -654,8 +659,8 @@ probe sunrpc.svc.recv.return = kernel.function("svc_recv").return ?, * @rq_proc: the procedure number in the request * @rq_prot: the IP protocol of the reqeust */ -probe sunrpc.svc.send = kernel.function("svc_send")?, - module("sunrpc").function("svc_send")? +probe sunrpc.svc.send = kernel.function("svc_send") !, + module("sunrpc").function("svc_send") { sv_name = kernel_string($rqstp->rq_server->sv_name) peer_ip = addr_from_rqst($rqstp) @@ -670,8 +675,8 @@ probe sunrpc.svc.send = kernel.function("svc_send")?, rq_xid, rq_prog, rq_vers, rq_proc, rq_prot) } -probe sunrpc.svc.send.return = kernel.function("svc_send").return ?, - module("sunrpc").function("svc_send").return ? +probe sunrpc.svc.send.return = kernel.function("svc_send").return !, + module("sunrpc").function("svc_send").return { name = "sunrpc.svc.send.return" retstr = returnstr(1) @@ -690,8 +695,8 @@ probe sunrpc.svc.send.return = kernel.function("svc_send").return ?, * @rq_proc: the procedure number in the request * @rq_prot: the IP protocol of the reqeust */ -probe sunrpc.svc.drop = kernel.function("svc_drop")?, - module("sunrpc").function("svc_drop")? +probe sunrpc.svc.drop = kernel.function("svc_drop") !, + module("sunrpc").function("svc_drop") { sv_name = kernel_string($rqstp->rq_server->sv_name) peer_ip = addr_from_rqst($rqstp) @@ -706,8 +711,8 @@ probe sunrpc.svc.drop = kernel.function("svc_drop")?, rq_xid, rq_prog, rq_vers, rq_proc, rq_prot) } -probe sunrpc.svc.drop.return = kernel.function("svc_drop").return ?, - module("sunrpc").function("svc_drop").return ? +probe sunrpc.svc.drop.return = kernel.function("svc_drop").return !, + module("sunrpc").function("svc_drop").return { name = "sunrpc.svc.drop.return" } @@ -741,8 +746,8 @@ probe sunrpc.sched.return = * @prot: the IP protocol in the RPC call * @tk_flags: the flags of the task */ -probe sunrpc.sched.new_task = kernel.function("rpc_new_task") ?, - module("sunrpc").function("rpc_new_task") ? +probe sunrpc.sched.new_task = kernel.function("rpc_new_task") !, + module("sunrpc").function("rpc_new_task") { xid = xid_from_clnt($clnt) prog = prog_from_clnt($clnt) @@ -754,8 +759,8 @@ probe sunrpc.sched.new_task = kernel.function("rpc_new_task") ?, argstr = sprintf("%d %d %d %d %d", xid, prog, vers, prot, flags) } -probe sunrpc.sched.new_task.return = kernel.function("rpc_new_task").return ?, - module("sunrpc").function("rpc_new_task").return ? +probe sunrpc.sched.new_task.return = kernel.function("rpc_new_task").return !, + module("sunrpc").function("rpc_new_task").return { name = "sunrpc.sched.new_task.return" retstr = returnstr(2) @@ -772,8 +777,8 @@ probe sunrpc.sched.new_task.return = kernel.function("rpc_new_task").return ?, * @prot: the IP protocol in the RPC call * @tk_flags: the flags of the task */ -probe sunrpc.sched.release_task = kernel.function("rpc_release_task") ?, - module("sunrpc").function("rpc_release_task") ? +probe sunrpc.sched.release_task = kernel.function("rpc_release_task") !, + module("sunrpc").function("rpc_release_task") { xid = xid_from_clnt($task->tk_client) prog = prog_from_clnt($task->tk_client) @@ -786,8 +791,8 @@ probe sunrpc.sched.release_task = kernel.function("rpc_release_task") ?, } probe sunrpc.sched.release_task.return = - kernel.function("rpc_release_task").return ?, - module("sunrpc").function("rpc_release_task").return ? + kernel.function("rpc_release_task").return !, + module("sunrpc").function("rpc_release_task").return { name = "sunrpc.sched.release_task.return" } @@ -805,8 +810,8 @@ probe sunrpc.sched.release_task.return = * @tk_pid: the debugging id of the task * @tk_flags: the flags of the task */ -probe sunrpc.sched.execute = kernel.function("__rpc_execute") ?, - module("sunrpc").function("__rpc_execute") ? +probe sunrpc.sched.execute = kernel.function("__rpc_execute") !, + module("sunrpc").function("__rpc_execute") { xid = xid_from_clnt($task->tk_client) prog = prog_from_clnt($task->tk_client) @@ -820,8 +825,8 @@ probe sunrpc.sched.execute = kernel.function("__rpc_execute") ?, tk_pid, tk_flags) } -probe sunrpc.sched.execute.return = kernel.function("__rpc_execute").return ?, - module("sunrpc").function("__rpc_execute").return ? +probe sunrpc.sched.execute.return = kernel.function("__rpc_execute").return !, + module("sunrpc").function("__rpc_execute").return { name = "sunrpc.sched.execute.return" @@ -845,8 +850,8 @@ probe sunrpc.sched.execute.return = kernel.function("__rpc_execute").return ?, * @tk_flags: the flags of the task * @delay: the time delayed */ -probe sunrpc.sched.delay = kernel.function("rpc_delay") ?, - module("sunrpc").function("rpc_delay") ? +probe sunrpc.sched.delay = kernel.function("rpc_delay") !, + module("sunrpc").function("rpc_delay") { xid = xid_from_clnt($task->tk_client) prog = prog_from_clnt($task->tk_client) @@ -861,8 +866,8 @@ probe sunrpc.sched.delay = kernel.function("rpc_delay") ?, prot, tk_pid, tk_flags, delay) } -probe sunrpc.sched.delay.return = kernel.function("rpc_delay").return ?, - module("sunrpc").function("rpc_delay").return ? +probe sunrpc.sched.delay.return = kernel.function("rpc_delay").return !, + module("sunrpc").function("rpc_delay").return { name = "sunrpc.sched.delay.return" } diff --git a/tapset/s390x/syscalls.stp b/tapset/s390x/syscalls.stp index 39236d79..07cb0577 100644 --- a/tapset/s390x/syscalls.stp +++ b/tapset/s390x/syscalls.stp @@ -103,7 +103,7 @@ probe syscall.sysctl32.return = kernel.function("sys32_sysctl").return ? { /* compat */ function get_32mmap_args:string (args:long) -%{ +%{ /* pure */ struct mmap_arg_struct_emu31 { u32 addr; u32 len; diff --git a/tapset/signal.stp b/tapset/signal.stp index 72ba9520..4fec7c13 100644 --- a/tapset/signal.stp +++ b/tapset/signal.stp @@ -37,8 +37,7 @@ */ probe signal.send = _signal.send.* { - sig=$sig - sig_name = _signal_name($sig) + sig_name = _signal_name(sig) sig_pid = task_pid(task) pid_name = task_execname(task) @@ -53,25 +52,35 @@ probe signal.send = _signal.send.* probe _signal.send.part1 = kernel.function("__group_send_sig_info") { name = "__group_send_sig_info" + sig = $sig task = $p sinfo = $info shared = 1 send2queue = 0 } +%( kernel_v <= "2.6.25" %? probe _signal.send.part2 = kernel.function("send_group_sigqueue") { name = "send_group_sigqueue" + sig = $sig task = $p sinfo = 0 # $q->info shared = 1 send2queue = 1 } +%) probe _signal.send.part3 = kernel.function("send_sigqueue") { name = "send_sigqueue" +%( kernel_v > "2.6.25" %? + task = $t + sig = $q->info->si_signo +%: task = $p + sig = $sig +%) sinfo = 0 # $q->info shared = 0 send2queue = 1 @@ -80,6 +89,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue") probe _signal.send.part4 = kernel.function("specific_send_sig_info") { name = "specific_send_sig_info" + sig = $sig task = $t sinfo = $info shared = 0 @@ -121,6 +131,7 @@ probe _signal.send.part4.return = kernel.function("specific_send_sig_info").retu send2queue = 0 } +%( kernel_v <= "2.6.25" %? /* * - return 0 if the signal is either sucessfully added into the * sigqueue of receiving process or a SI_TIMER entry is already @@ -135,6 +146,7 @@ probe _signal.send.part2.return = kernel.function("send_group_sigqueue").return shared = 1 send2queue = 1 } +%) /* * - return 0 if the signal is either sucessfully added into the @@ -224,7 +236,7 @@ probe signal.check_ignored = kernel.function("sig_ignored") sig_name = _signal_name($sig) } -probe signal.check_ignored.return = kernel.function("sig_ignored").return +probe signal.check_ignored.return = kernel.function("sig_ignored").return ? { name = "sig_ignored" retstr = returnstr(1) @@ -336,7 +348,7 @@ probe signal.systkill.return = syscall.tkill.return */ probe signal.send_sig_queue = kernel.function("send_sigqueue"), - kernel.function("send_group_sigqueue") + kernel.function("send_group_sigqueue") ? { sig = $sig sig_name = _signal_name($sig) @@ -347,7 +359,7 @@ probe signal.send_sig_queue = probe signal.send_sig_queue.return = kernel.function("send_sigqueue").return, - kernel.function("send_group_sigqueue").return + kernel.function("send_group_sigqueue").return ? { retstr = returnstr(1) } diff --git a/tapset/syscalls.stp b/tapset/syscalls.stp index d394208f..11c2bdf7 100644 --- a/tapset/syscalls.stp +++ b/tapset/syscalls.stp @@ -630,7 +630,8 @@ probe syscall.exit = kernel.function("do_exit") { status = $code argstr = sprint($code) } -probe syscall.exit.return = end {} +# sys_exit() never returns, and is blacklisted for return probes, +# so no alias here. See bz6588. # exit_group _________________________________________________ # void sys_exit_group(int error_code) @@ -640,8 +641,26 @@ probe syscall.exit_group = kernel.function("sys_exit_group") { status = $error_code argstr = sprint($error_code) } +# sys_exit_group() never returns, and is blacklisted for return probes, +# so no alias here. See bz6588. -probe syscall.exit_group.return = end {} +# faccessat __________________________________________________ +# new function with 2.6.16 +# long sys_faccessat(int dfd, const char __user *filename, int mode) +probe syscall.faccessat = kernel.function("sys_faccessat") ? { + name = "faccessat" + dfd = $dfd + dfd_str = _dfd_str($dfd) + filename = $filename + filename_str = user_string($filename) + mode = $mode + mode_str = _access_mode_str($mode) + argstr = sprintf("%s, %s, %s", dfd_str, user_string_quoted($filename), mode_str) +} +probe syscall.faccessat.return = kernel.function("sys_faccessat").return ? { + name = "faccessat" + retstr = returnstr(1) +} %(arch != "x86_64" %? # fadvise64 __________________________________________________ @@ -736,6 +755,24 @@ probe syscall.fchmod.return = kernel.function("sys_fchmod").return { retstr = returnstr(1) } +# fchmodat ___________________________________________________ +# new function with 2.6.16 +# long sys_fchmodat(int dfd, const char __user *filename, +# mode_t mode) +probe syscall.fchmodat = kernel.function("sys_fchmodat") ? { + name = "fchmodat" + dfd = $dfd + dfd_str = _dfd_str($dfd) + filename = $filename + filename_str = user_string($filename) + mode = $mode + argstr = sprintf("%s, %s, %#o", dfd_str, user_string_quoted($filename), $mode) +} +probe syscall.fchmodat.return = kernel.function("sys_fchmodat").return ? { + name = "fchmodat" + retstr = returnstr(1) +} + # fchown _____________________________________________________ # long sys_fchown(unsigned int fd, uid_t user, gid_t group) probe syscall.fchown = kernel.function("sys_fchown") { @@ -764,6 +801,28 @@ probe syscall.fchown16.return = kernel.function("sys_fchown16").return ? { retstr = returnstr(1) } +# fchownat ___________________________________________________ +# new function with 2.6.16 +# long sys_fchownat(int dfd, const char __user *filename, +# uid_t user, gid_t group, int flag) +probe syscall.fchownat = kernel.function("sys_fchownat") ? { + name = "fchownat" + dfd = $dfd + dfd_str = _dfd_str($dfd) + filename = $filename + filename_str = user_string($filename) + user = __int32($user) + group = __int32($group) + flag = $flag + flag_str = _at_flag_str($flag) + argstr = sprintf("%s, %s, %d, %d, %s", + dfd_str, user_string_quoted($filename), user, group, flag_str) +} +probe syscall.fchownat.return = kernel.function("sys_fchownat").return ? { + name = "fchownat" + retstr = returnstr(1) +} + # fcntl ______________________________________________________ # long sys_fcntl(int fd, unsigned int cmd, unsigned long arg) # long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -2013,6 +2072,7 @@ probe syscall.lchown16.return = kernel.function("sys_lchown16").return ? { name = "lchown16" retstr = returnstr(1) } + # lgetxattr __________________________________________________ # ssize_t sys_lgetxattr(char __user *path, # char __user *name, @@ -2035,6 +2095,7 @@ probe syscall.lgetxattr.return = kernel.function("sys_lgetxattr").return { name = "lgetxattr" retstr = returnstr(1) } + # link _______________________________________________________ # long sys_link(const char __user * oldname, # const char __user * newname) @@ -2051,6 +2112,32 @@ probe syscall.link.return = kernel.function("sys_link").return { retstr = returnstr(1) } +# linkat _____________________________________________________ +# new function with 2.6.16 +# long sys_linkat(int olddfd, const char __user *oldname, +# int newdfd, const char __user *newname, int flags) +probe syscall.linkat = kernel.function("sys_linkat") ? { + name = "linkat" + olddfd = $olddfd + olddfd_str = _dfd_str($olddfd) + oldname = $oldname + oldname_str = user_string($oldname) + newdfd = $newdfd + newdfd_str = _dfd_str($newdfd) + newname = $newname + newname_str = user_string($newname) + flags = $flags + flags_str = _at_flag_str($flags) + argstr = sprintf("%s, %s, %s, %s, %s", + olddfd_str, user_string_quoted($oldname), + newdfd_str, user_string_quoted($newname), + flags_str) +} +probe syscall.linkat.return = kernel.function("sys_linkat").return ? { + name = "linkat" + retstr = returnstr(1) +} + # listen _____________________________________________________ # long sys_listen(int fd, int backlog) probe syscall.listen = kernel.function("sys_listen") ? { @@ -2328,7 +2415,7 @@ probe syscall.mkdirat = kernel.function("sys_mkdirat") ? { dirfd = $dfd pathname = user_string($pathname) mode = $mode - argstr = sprintf("%d, %s, %#o", $dfd, user_string_quoted($pathname), $mode) + argstr = sprintf("%s, %s, %#o", _dfd_str($dfd), user_string_quoted($pathname), $mode) } probe syscall.mkdirat.return = kernel.function("sys_mkdirat").return ? { name = "mkdirat" @@ -2350,6 +2437,27 @@ probe syscall.mknod.return = kernel.function("sys_mknod").return { retstr = returnstr(1) } +# mknodat ____________________________________________________ +# new function with 2.6.16 +# long sys_mknodat(int dfd, const char __user *filename, +# int mode, unsigned dev) +probe syscall.mknodat = kernel.function("sys_mknodat") ? { + name = "mknodat" + dfd = $dfd + dfd_str = _dfd_str($dfd) + filename = $filename + filename_str = user_string($filename) + mode = $mode + mode_str = _mknod_mode_str($mode) + dev = $dev + argstr = sprintf("%s, %s, %s, %p", + dfd_str, user_string_quoted($filename), mode_str, $dev) +} +probe syscall.mknodat.return = kernel.function("sys_mknodat").return ? { + name = "mknodat" + retstr = returnstr(1) +} + # mlock ______________________________________________________ # # long sys_mlock(unsigned long start, size_t len) diff --git a/tapset/syscalls2.stp b/tapset/syscalls2.stp index 0db50347..98bdc95f 100644 --- a/tapset/syscalls2.stp +++ b/tapset/syscalls2.stp @@ -2853,6 +2853,20 @@ probe syscall.unlink.return = kernel.function("sys_unlink").return { name = "unlink" retstr = returnstr(1) } + +# unshare ____________________________________________________ +# new function with 2.6.16 +# long sys_unshare(unsigned long unshare_flags) +probe syscall.unshare = kernel.function("sys_unshare") ? { + name = "unshare" + unshare_flags = $unshare_flags + argstr = __fork_flags(unshare_flags) +} +probe syscall.unshare.return = kernel.function("sys_unshare").return ? { + name = "unshare" + retstr = returnstr(1) +} + # uselib _____________________________________________________ # # asmlinkage long diff --git a/tapset/task.stp b/tapset/task.stp index a15888f8..d89729e8 100644 --- a/tapset/task.stp +++ b/tapset/task.stp @@ -9,6 +9,9 @@ %{ #include <linux/version.h> #include <linux/file.h> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) +#include <linux/fdtable.h> +#endif %} // Return the task_struct representing the current process diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp index a5aba55a..99c39e18 100644 --- a/tapset/x86_64/registers.stp +++ b/tapset/x86_64/registers.stp @@ -38,7 +38,7 @@ function _stp_register_regs() { _stp_regs_registered = 1 } -function _stp_get_register_by_offset:long (offset:long) %{ +function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); THIS->__retvalue = value; @@ -48,12 +48,16 @@ function _stp_get_register_by_offset:long (offset:long) %{ * _stp_sign_extend32() is callable from a script function. * __stp_sign_extend32() (in regs.c) is callable from a C function. */ -function _stp_sign_extend32:long (value:long) %{ +function _stp_sign_extend32:long (value:long) %{ /* pure */ THIS->__retvalue = __stp_sign_extend32(THIS->value); %} function _stp_register:long (name:string, sign_extend:long) { reg32 = 0 + if (!registers_valid()) { + error("cannot access CPU registers in this context") + return 0 + } if (!_stp_regs_registered) _stp_register_regs() offset = _reg_offsets[name] @@ -94,7 +98,7 @@ function u_register:long (name:string) { * If sign_extend=1 and (truncate=1 or the probepoint we've hit is in a * 32-bit app), sign-extend the 32-bit value. */ -function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ +function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ /* pure */ long val; int result, n, nr_regargs; size_t argsz = sizeof(long); @@ -166,7 +170,7 @@ deref_fault: /* branched to from deref() */ } %} -function probing_32bit_app() %{ +function probing_32bit_app() %{ /* pure */ THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); %} @@ -227,7 +231,7 @@ function asmlinkage() { function fastcall() { } -function regparm(n) %{ +function regparm(n:long) %{ if (_stp_probing_32bit_app(CONTEXT->regs) && (THIS->n < 0 || THIS->n > 3)) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), @@ -239,5 +243,9 @@ function regparm(n) %{ "For x86_64, regparm value must be in the range 0-6."); CONTEXT->last_error = CONTEXT->error_buffer; } else - CONTEXT->regparm = _STP_REGPARM | (int) n; + CONTEXT->regparm = _STP_REGPARM | (int) THIS->n; %} + +function syscall_nr:long() { + return _stp_register("orig_ax", 1) +} diff --git a/tapsets.cxx b/tapsets.cxx index 54b951cd..a45233fc 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -14,6 +14,7 @@ #include "translate.h" #include "session.h" #include "util.h" +#include "dwarf_wrappers.h" #include <cstdlib> #include <algorithm> @@ -61,7 +62,6 @@ extern "C" { using namespace std; using namespace __gnu_cxx; - // ------------------------------------------------------------------------ // Generic derived_probe_group: contains an ordinary vector of the // given type. It provides only the enrollment function. @@ -81,6 +81,10 @@ public: // begin/end/error probes are run right during registration / deregistration // ------------------------------------------------------------------------ +static string TOK_BEGIN("begin"); +static string TOK_END("end"); +static string TOK_ERROR("error"); + enum be_t { BEGIN, END, ERROR }; struct be_derived_probe: public derived_probe @@ -116,7 +120,6 @@ public: void emit_module_exit (systemtap_session& s); }; - struct be_builder: public derived_probe_builder { be_t type; @@ -126,13 +129,13 @@ struct be_builder: public derived_probe_builder virtual void build(systemtap_session &, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { int64_t priority; - if ((type == BEGIN && !get_param(parameters, "begin", priority)) || - (type == END && !get_param(parameters, "end", priority)) || - (type == ERROR && !get_param(parameters, "error", priority))) + if ((type == BEGIN && !get_param(parameters, TOK_BEGIN, priority)) || + (type == END && !get_param(parameters, TOK_END, priority)) || + (type == ERROR && !get_param(parameters, TOK_ERROR, priority))) priority = 0; finished_results.push_back( new be_derived_probe(base, location, type, priority)); @@ -414,6 +417,8 @@ be_derived_probe_group::emit_module_exit (systemtap_session& s) // never probes are never run // ------------------------------------------------------------------------ +static string TOK_NEVER("never"); + struct never_derived_probe: public derived_probe { never_derived_probe (probe* p): derived_probe (p) {} @@ -428,7 +433,7 @@ struct never_builder: public derived_probe_builder virtual void build(systemtap_session &, probe * base, probe_point * location, - std::map<std::string, literal *> const &, + literal_map_t const &, vector<derived_probe *> & finished_results) { finished_results.push_back(new never_derived_probe(base, location)); @@ -472,7 +477,7 @@ struct func_info { func_info() - : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0) + : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0), weak(false) { memset(&die, 0, sizeof(die)); } @@ -482,6 +487,7 @@ func_info Dwarf_Die die; Dwarf_Addr addr; Dwarf_Addr prologue_end; + bool weak; }; struct @@ -503,6 +509,7 @@ struct dwarf_query; // forward decls struct dwflpp; struct symbol_table; + struct module_info { @@ -559,13 +566,20 @@ symbol_table module_info *mod_info; // associated module map<string, func_info*> map_by_name; vector<func_info*> list_by_addr; +#ifdef __powerpc__ + GElf_Word opd_section; +#endif - void add_symbol(const char *name, Dwarf_Addr addr, Dwarf_Addr *high_addr); + void add_symbol(const char *name, bool weak, Dwarf_Addr addr, + Dwarf_Addr *high_addr); enum info_status read_symbols(FILE *f, const string& path); enum info_status read_from_elf_file(const string& path); enum info_status read_from_text_file(const string& path); enum info_status get_from_elf(); + void prepare_section_rejection(Dwfl_Module *mod); + bool reject_section(GElf_Word section); void mark_dwarf_redundancies(dwflpp *dw); + void purge_syscall_stubs(); func_info *lookup_symbol(const string& name); Dwarf_Addr lookup_symbol_address(const string& name); func_info *get_func_containing_address(Dwarf_Addr addr); @@ -595,6 +609,8 @@ dwarf_diename_integrate (Dwarf_Die *die) return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); } +enum line_t { ABSOLUTE, RELATIVE, RANGE, WILDCARD }; + struct dwflpp { systemtap_session & sess; @@ -816,35 +832,6 @@ struct dwflpp return t; } - - // NB: "rc == 0" means OK in this case - static void dwfl_assert(string desc, int rc, string extra_msg = "") - { - string msg = "libdwfl failure (" + desc + "): "; - if (rc < 0) msg += dwfl_errmsg (rc); - else if (rc > 0) msg += strerror (rc); - if (rc != 0) - { - if (extra_msg.length() > 0) - msg += "\n" + extra_msg; - throw semantic_error (msg); - } - } - - void dwarf_assert(string desc, int rc) // NB: "rc == 0" means OK in this case - { - string msg = "libdw failure (" + desc + "): "; - if (rc < 0) msg += dwarf_errmsg (rc); - else if (rc > 0) msg += strerror (rc); - if (rc != 0) - throw semantic_error (msg); - } - - // static so pathname_caching_callback() can access them - static module_cache_t module_cache; - static bool ignore_vmlinux; - - dwflpp(systemtap_session & session) : sess(session), @@ -858,7 +845,6 @@ struct dwflpp cu(NULL), function(NULL) { - ignore_vmlinux = sess.ignore_vmlinux; } // Called by dwfl_linux_kernel_report_offline(). We may not have @@ -867,12 +853,16 @@ struct dwflpp // (Currently, we get all the elf info we need via elfutils -- if the // elf file exists -- so remembering the pathname isn't strictly needed. // But we still need to handle the case where there's no vmlinux.) + + static systemtap_session* this_session; // XXX: used only due to elfutils shortcoming + static int pathname_caching_callback(const char *name, const char *path) { module_info *mi = new module_info(name); - module_cache.cache[name] = mi; + assert (this_session); + this_session->module_cache->cache[name] = mi; - if (ignore_vmlinux && path && name == TOK_KERNEL) + if (this_session->ignore_vmlinux && path && name == TOK_KERNEL) { // report_kernel() in elfutils found vmlinux, but pretend it didn't. // Given a non-null path, returning 1 means keep reporting modules. @@ -894,12 +884,17 @@ struct dwflpp void setup(bool kernel, bool debuginfo_needed = true) { + if (! sess.module_cache) + sess.module_cache = new module_cache (); + // XXX: this is where the session -R parameter could come in static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build"; static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); static char *debuginfo_path = (debuginfo_env_arr ? debuginfo_env_arr : debuginfo_path_arr); + static const char *debug_path = (debuginfo_env_arr ? + debuginfo_env_arr : sess.kernel_release.c_str()); static const Dwfl_Callbacks proc_callbacks = { @@ -925,17 +920,24 @@ struct dwflpp dwfl_report_begin (dwfl); int (*callback)(const char *name, const char *path); - if (sess.consult_symtab && !module_cache.paths_collected) + if (sess.consult_symtab && !sess.module_cache->paths_collected) { callback = pathname_caching_callback; - module_cache.paths_collected = true; + sess.module_cache->paths_collected = true; } else callback = NULL; + + // XXX: we should not need to set this static variable just + // for the callback. The following elfutils routine should + // take some void* parameter to pass context to the callback. + this_session = & sess; int rc = dwfl_linux_kernel_report_offline (dwfl, - sess.kernel_release.c_str(), + debug_path, /* selection predicate */ callback); + this_session = 0; + if (debuginfo_needed) dwfl_assert (string("missing kernel ") + sess.kernel_release + @@ -983,10 +985,13 @@ struct dwflpp Dwarf_Addr addr, void *param) { - module_cache_t *cache = static_cast<module_cache_t*>(param); + systemtap_session *sess = static_cast<systemtap_session*>(param); + module_cache_t *cache = sess->module_cache; module_info *mi = NULL; - if (ignore_vmlinux && name == TOK_KERNEL) + assert (cache); + + if (sess->ignore_vmlinux && name == TOK_KERNEL) // This wouldn't be called for vmlinux if vmlinux weren't there. return DWARF_CB_OK; @@ -1004,18 +1009,18 @@ struct dwflpp void cache_modules_dwarf() { - if (!module_cache.dwarf_collected) + if (!sess.module_cache->dwarf_collected) { ptrdiff_t off = 0; do { if (pending_interrupts) return; off = dwfl_getmodules (dwfl, module_caching_callback, - & module_cache, off); + & sess, off); } while (off > 0); - dwfl_assert("dwfl_getmodules", off); - module_cache.dwarf_collected = true; + dwfl_assert("dwfl_getmodules", off == 0); + sess.module_cache->dwarf_collected = true; } } @@ -1027,7 +1032,7 @@ struct dwflpp cache_modules_dwarf(); map<string, module_info*>::iterator i; - for (i = module_cache.cache.begin(); i != module_cache.cache.end(); i++) + for (i = sess.module_cache->cache.begin(); i != sess.module_cache->cache.end(); i++) { if (pending_interrupts) return; module_info *mi = i->second; @@ -1143,105 +1148,121 @@ struct dwflpp bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno); void iterate_over_srcfile_lines (char const * srcfile, - int lineno, + int lines[2], bool need_single_match, - void (* callback) (Dwarf_Line * line, void * arg), + enum line_t line_type, + void (* callback) (const dwarf_line_t& line, + void * arg), void *data) { Dwarf_Line **srcsp = NULL; size_t nsrcs = 0; dwarf_query * q = static_cast<dwarf_query *>(data); + int lineno = lines[0]; get_module_dwarf(); - dwarf_assert ("dwarf_getsrc_file", - dwarf_getsrc_file (module_dwarf, - srcfile, lineno, 0, - &srcsp, &nsrcs)); + if (line_type == RELATIVE) + { + Dwarf_Addr addr; + Dwarf_Line *line; + int line_number; + + dwarf_assert ("dwarf_entrypc", dwarf_entrypc (this->function, &addr)); + line = dwarf_getsrc_die (this->cu, addr); + dwarf_assert ("dwarf_getsrc_die", line == NULL); + dwarf_assert ("dwarf_lineno", dwarf_lineno (line, &line_number)); + lineno += line_number; + } + else if (line_type == WILDCARD) + function_line (&lineno); + + for (int l = lineno; ; l = l + 1) + { + dwarf_assert ("dwarf_getsrc_file", + dwarf_getsrc_file (module_dwarf, + srcfile, l, 0, + &srcsp, &nsrcs)); - // NB: Formerly, we used to filter, because: + if (line_type == WILDCARD || line_type == RANGE) + { + Dwarf_Addr line_addr; + dwarf_lineno (srcsp [0], &lineno); + if (lineno != l) + continue; + dwarf_lineaddr (srcsp [0], &line_addr); + if (dwarf_haspc (function, line_addr) != 1) + break; + } - // dwarf_getsrc_file gets one *near hits* for line numbers, not - // exact matches. For example, an existing file but a nonexistent - // line number will be rounded up to the next definition in that - // file. This may be similar to the GDB breakpoint algorithm, but - // we don't want to be so fuzzy in systemtap land. So we filter. + // NB: Formerly, we used to filter, because: - // But we now see the error of our ways, and skip this filtering. + // dwarf_getsrc_file gets one *near hits* for line numbers, not + // exact matches. For example, an existing file but a nonexistent + // line number will be rounded up to the next definition in that + // file. This may be similar to the GDB breakpoint algorithm, but + // we don't want to be so fuzzy in systemtap land. So we filter. - // XXX: the code also fails to match e.g. inline function - // definitions when the srcfile is a header file rather than the - // CU name. + // But we now see the error of our ways, and skip this filtering. - size_t remaining_nsrcs = nsrcs; -#if 0 - for (size_t i = 0; i < nsrcs; ++i) - { - int l_no; - Dwarf_Line* l = srcsp[i]; - dwarf_assert ("dwarf_lineno", dwarf_lineno (l, & l_no)); - if (l_no != lineno) - { - if (sess.verbose > 3) - clog << "skipping line number mismatch " - << "(" << l_no << " vs " << lineno << ")" - << " in file '" << srcfile << "'" - << "\n"; - srcsp[i] = 0; - remaining_nsrcs --; - } - } -#endif + // XXX: the code also fails to match e.g. inline function + // definitions when the srcfile is a header file rather than the + // CU name. - if (need_single_match && remaining_nsrcs > 1) - { - // We wanted a single line record (a unique address for the - // line) and we got a bunch of line records. We're going to - // skip this probe (throw an exception) but before we throw - // we're going to look around a bit to see if there's a low or - // high line number nearby which *doesn't* have this problem, - // so we can give the user some advice. - - int lo_try = -1; - int hi_try = -1; - for (size_t i = 1; i < 6; ++i) + size_t remaining_nsrcs = nsrcs; + + if (need_single_match && remaining_nsrcs > 1) { - if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i)) - lo_try = lineno - i; + // We wanted a single line record (a unique address for the + // line) and we got a bunch of line records. We're going to + // skip this probe (throw an exception) but before we throw + // we're going to look around a bit to see if there's a low or + // high line number nearby which *doesn't* have this problem, + // so we can give the user some advice. + + int lo_try = -1; + int hi_try = -1; + for (size_t i = 1; i < 6; ++i) + { + if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i)) + lo_try = lineno - i; - if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i)) - hi_try = lineno + i; - } + if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i)) + hi_try = lineno + i; + } - stringstream advice; - advice << "multiple addresses for " << srcfile << ":" << lineno; - if (lo_try > 0 || hi_try > 0) - { - advice << " (try "; - if (lo_try > 0) - advice << srcfile << ":" << lo_try; - if (lo_try > 0 && hi_try > 0) - advice << " or "; - if (hi_try > 0) - advice << srcfile << ":" << hi_try; - advice << ")"; - } - throw semantic_error (advice.str()); - } + stringstream advice; + advice << "multiple addresses for " << srcfile << ":" << lineno; + if (lo_try > 0 || hi_try > 0) + { + advice << " (try "; + if (lo_try > 0) + advice << srcfile << ":" << lo_try; + if (lo_try > 0 && hi_try > 0) + advice << " or "; + if (hi_try > 0) + advice << srcfile << ":" << hi_try; + advice << ")"; + } + throw semantic_error (advice.str()); + } - try - { - for (size_t i = 0; i < nsrcs; ++i) + try { - if (pending_interrupts) return; - if (srcsp [i]) // skip over mismatched lines - callback (srcsp[i], data); + for (size_t i = 0; i < nsrcs; ++i) + { + if (pending_interrupts) return; + if (srcsp [i]) // skip over mismatched lines + callback (dwarf_line_t(srcsp[i]), data); + } } - } - catch (...) - { - free (srcsp); - throw; + catch (...) + { + free (srcsp); + throw; + } + if (line_type != WILDCARD || l == lines[1]) + break; } free (srcsp); } @@ -1316,23 +1337,23 @@ struct dwflpp if (func->decl_file == 0) func->decl_file = ""; unsigned entrypc_srcline_idx = 0; - Dwarf_Line* entrypc_srcline = 0; + dwarf_line_t entrypc_srcline; // open-code binary search for exact match { unsigned l = 0, h = nlines; while (l < h) { entrypc_srcline_idx = (l + h) / 2; - Dwarf_Addr addr; - Dwarf_Line *lr = dwarf_onesrcline(lines, entrypc_srcline_idx); - dwarf_lineaddr (lr, &addr); + const dwarf_line_t lr(dwarf_onesrcline(lines, + entrypc_srcline_idx)); + Dwarf_Addr addr = lr.addr(); if (addr == entrypc) { entrypc_srcline = lr; break; } else if (l + 1 == h) { break; } // ran off bottom of tree else if (addr < entrypc) { l = entrypc_srcline_idx; } else { h = entrypc_srcline_idx; } } } - if (entrypc_srcline == 0) + if (!entrypc_srcline) throw semantic_error ("missing entrypc dwarf line record for function '" + func->name + "'"); @@ -1357,13 +1378,10 @@ struct dwflpp bool ranoff_end = false; while (postprologue_srcline_idx < nlines) { - Dwarf_Addr postprologue_addr; - Dwarf_Line *lr = dwarf_onesrcline(lines, postprologue_srcline_idx); - dwarf_lineaddr (lr, &postprologue_addr); - const char* postprologue_file = dwarf_linesrc (lr, NULL, NULL); - int postprologue_lineno; - dwfl_assert ("dwarf_lineno", - dwarf_lineno (lr, & postprologue_lineno)); + dwarf_line_t lr(dwarf_onesrcline(lines, postprologue_srcline_idx)); + Dwarf_Addr postprologue_addr = lr.addr(); + const char* postprologue_file = lr.linesrc(); + int postprologue_lineno = lr.lineno(); if (sess.verbose>2) clog << "checking line record 0x" << hex << postprologue_addr << dec @@ -1485,9 +1503,9 @@ struct dwflpp dwarf_decl_line (function, linep); } - bool die_has_pc (Dwarf_Die * die, Dwarf_Addr pc) + bool die_has_pc (Dwarf_Die & die, Dwarf_Addr pc) { - int res = dwarf_haspc (die, pc); + int res = dwarf_haspc (&die, pc); if (res == -1) dwarf_assert ("dwarf_haspc", res); return res == 1; @@ -1524,19 +1542,19 @@ struct dwflpp // We emit a comment approximating the variable+offset expression that // relocatable module probing code will need to have. Dwfl_Module *mod = dwfl_addrmodule (dwfl, address); - dwfl_assert ("dwfl_addrmodule", mod == NULL); + dwfl_assert ("dwfl_addrmodule", mod); int n = dwfl_module_relocations (mod); - dwfl_assert ("dwfl_module_relocations", n < 0); + dwfl_assert ("dwfl_module_relocations", n >= 0); int i = dwfl_module_relocate_address (mod, &address); - dwfl_assert ("dwfl_module_relocate_address", i < 0); + dwfl_assert ("dwfl_module_relocate_address", i >= 0); const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - dwfl_assert ("dwfl_module_info", modname == NULL); + dwfl_assert ("dwfl_module_info", modname); const char *secname = dwfl_module_relocation_info (mod, i, NULL); if (n > 0 && !(n == 1 && secname == NULL)) { - dwfl_assert ("dwfl_module_relocation_info", secname == NULL); + dwfl_assert ("dwfl_module_relocation_info", secname); if (n > 1 || secname[0] != '\0') { // This gives us the module name, and section name within the @@ -1581,7 +1599,6 @@ struct dwflpp void print_locals(Dwarf_Die *die, ostream &o) { // Try to get the first child of die. - bool local_found = false; Dwarf_Die child; if (dwarf_child (die, &child) == 0) { @@ -1594,7 +1611,6 @@ struct dwflpp case DW_TAG_variable: case DW_TAG_formal_parameter: o << " " << dwarf_diename (&child); - local_found = true; break; default: break; @@ -1602,9 +1618,6 @@ struct dwflpp } while (dwarf_siblingof (&child, &child) == 0); } - - if (! local_found) - o << " (none found)"; } Dwarf_Attribute * @@ -1642,8 +1655,7 @@ struct dwflpp print_locals (scopes, alternatives); throw semantic_error ("unable to find local '" + local + "'" + " near pc " + lex_cast_hex<string>(pc) - + " (alternatives:" + alternatives.str () - + ")"); + + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")"))); } for (int inner = 0; inner < nscopes; ++inner) @@ -2177,8 +2189,10 @@ struct dwflpp } }; -module_cache_t dwflpp::module_cache; -bool dwflpp::ignore_vmlinux = false; + +systemtap_session* dwflpp::this_session = 0; // XXX: used only due to elfutils shortcoming + + enum @@ -2252,7 +2266,7 @@ struct base_query probe * base_probe, probe_point * base_loc, dwflpp & dw, - map<string, literal *> const & params, + literal_map_t const & params, vector<derived_probe *> & results); virtual ~base_query() {} @@ -2263,13 +2277,13 @@ struct base_query vector<derived_probe *> & results; // Parameter extractors. - static bool has_null_param(map<string, literal *> const & params, + static bool has_null_param(literal_map_t const & params, string const & k); - static bool get_string_param(map<string, literal *> const & params, + static bool get_string_param(literal_map_t const & params, string const & k, string & v); - static bool get_number_param(map<string, literal *> const & params, + static bool get_number_param(literal_map_t const & params, string const & k, long & v); - static bool get_number_param(map<string, literal *> const & params, + static bool get_number_param(literal_map_t const & params, string const & k, Dwarf_Addr & v); // Extracted parameters. @@ -2284,7 +2298,7 @@ base_query::base_query(systemtap_session & sess, probe * base_probe, probe_point * base_loc, dwflpp & dw, - map<string, literal *> const & params, + literal_map_t const & params, vector<derived_probe *> & results) : sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw), results(results) @@ -2301,7 +2315,7 @@ base_query::base_query(systemtap_session & sess, } bool -base_query::has_null_param(map<string, literal *> const & params, +base_query::has_null_param(literal_map_t const & params, string const & k) { return derived_probe_builder::has_null_param(params, k); @@ -2309,7 +2323,7 @@ base_query::has_null_param(map<string, literal *> const & params, bool -base_query::get_string_param(map<string, literal *> const & params, +base_query::get_string_param(literal_map_t const & params, string const & k, string & v) { return derived_probe_builder::get_param (params, k, v); @@ -2317,7 +2331,7 @@ base_query::get_string_param(map<string, literal *> const & params, bool -base_query::get_number_param(map<string, literal *> const & params, +base_query::get_number_param(literal_map_t const & params, string const & k, long & v) { int64_t value; @@ -2328,7 +2342,7 @@ base_query::get_number_param(map<string, literal *> const & params, bool -base_query::get_number_param(map<string, literal *> const & params, +base_query::get_number_param(literal_map_t const & params, string const & k, Dwarf_Addr & v) { int64_t value; @@ -2337,6 +2351,8 @@ base_query::get_number_param(map<string, literal *> const & params, return present; } +typedef map<Dwarf_Addr, inline_instance_info> inline_instance_map_t; +typedef map<Dwarf_Addr, func_info> func_info_map_t; struct dwarf_query : public base_query { @@ -2344,7 +2360,7 @@ struct dwarf_query : public base_query probe * base_probe, probe_point * base_loc, dwflpp & dw, - map<string, literal *> const & params, + literal_map_t const & params, vector<derived_probe *> & results); virtual void handle_query_module(); @@ -2404,14 +2420,15 @@ struct dwarf_query : public base_query function_spec_type spec_type; string function; string file; - int line; + line_t line_type; + int line[2]; bool query_done; // Found exact match set<char const *> filtered_srcfiles; // Map official entrypc -> func_info object - map<Dwarf_Addr, inline_instance_info> filtered_inlines; - map<Dwarf_Addr, func_info> filtered_functions; + inline_instance_map_t filtered_inlines; + func_info_map_t filtered_functions; bool choose_next_line; Dwarf_Addr entrypc_for_next_line; }; @@ -2451,14 +2468,13 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen // We also try to filter out lines that leave the selected // functions (if any). - Dwarf_Line *line = srcsp[0]; - Dwarf_Addr addr; - dwarf_lineaddr (line, &addr); + dwarf_line_t line(srcsp[0]); + Dwarf_Addr addr = line.addr(); - for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); + for (func_info_map_t::iterator i = q->filtered_functions.begin(); i != q->filtered_functions.end(); ++i) { - if (q->dw.die_has_pc (&(i->second.die), addr)) + if (q->dw.die_has_pc (i->second.die, addr)) { if (q->sess.verbose>4) clog << "alternative line " << lineno << " accepted: fn=" << i->second.name << endl; @@ -2466,10 +2482,10 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen } } - for (map<Dwarf_Addr, inline_instance_info>::iterator i = q->filtered_inlines.begin(); + for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) { - if (q->dw.die_has_pc (&(i->second.die), addr)) + if (q->dw.die_has_pc (i->second.die, addr)) { if (sess.verbose>4) clog << "alternative line " << lineno << " accepted: ifn=" << i->second.name << endl; @@ -2570,7 +2586,7 @@ struct dwarf_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results); }; @@ -2579,7 +2595,7 @@ dwarf_query::dwarf_query(systemtap_session & sess, probe * base_probe, probe_point * base_loc, dwflpp & dw, - map<string, literal *> const & params, + literal_map_t const & params, vector<derived_probe *> & results) : base_query(sess, base_probe, base_loc, dw, params, results) { @@ -2871,11 +2887,12 @@ dwarf_query::parse_function_spec(string & spec) function.clear(); file.clear(); - line = 0; + line[0] = 0; + line[1] = 0; while (i != e && *i != '@') { - if (*i == ':') + if (*i == ':' || *i == '+') goto bad; function += *i++; } @@ -2892,8 +2909,17 @@ dwarf_query::parse_function_spec(string & spec) if (i++ == e) goto bad; - while (i != e && *i != ':') + while (i != e && *i != ':' && *i != '+') file += *i++; + if (*i == ':') + { + if (*(i + 1) == '*') + line_type = WILDCARD; + else + line_type = ABSOLUTE; + } + else if (*i == '+') + line_type = RELATIVE; if (i == e) { @@ -2910,7 +2936,22 @@ dwarf_query::parse_function_spec(string & spec) try { - line = lex_cast<int>(string(i, e)); + if (line_type != WILDCARD) + { + string::const_iterator dash = i; + + while (dash != e && *dash != '-') + dash++; + if (dash == e) + line[0] = line[1] = lex_cast<int>(string(i, e)); + else + { + line_type = RANGE; + line[0] = lex_cast<int>(string(i, dash)); + line[1] = lex_cast<int>(string(dash + 1, e)); + } + } + if (sess.verbose>2) clog << "parsed '" << spec << "' -> func '"<< function @@ -3016,7 +3057,7 @@ string dwarf_query::get_blacklist_section(Dwarf_Addr addr) { Elf_Scn* scn = 0; size_t shstrndx; - dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); + dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); while ((scn = elf_nextscn (elf, scn)) != NULL) { GElf_Shdr shdr_mem; @@ -3268,20 +3309,18 @@ query_func_info (Dwarf_Addr entrypc, static void -query_srcfile_line (Dwarf_Line * line, void * arg) +query_srcfile_line (const dwarf_line_t& line, void * arg) { dwarf_query * q = static_cast<dwarf_query *>(arg); - Dwarf_Addr addr; - dwarf_lineaddr(line, &addr); + Dwarf_Addr addr = line.addr(); - int lineno; - dwarf_lineno (line, &lineno); + int lineno = line.lineno(); - for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); + for (func_info_map_t::iterator i = q->filtered_functions.begin(); i != q->filtered_functions.end(); ++i) { - if (q->dw.die_has_pc (&(i->second.die), addr)) + if (q->dw.die_has_pc (i->second.die, addr)) { if (q->sess.verbose>3) clog << "function DIE lands on srcfile\n"; @@ -3294,17 +3333,17 @@ query_srcfile_line (Dwarf_Line * line, void * arg) } } - for (map<Dwarf_Addr, inline_instance_info>::iterator i + for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) { - if (q->dw.die_has_pc (&(i->second.die), addr)) + if (q->dw.die_has_pc (i->second.die, addr)) { if (q->sess.verbose>3) clog << "inline instance DIE lands on srcfile\n"; if (q->has_statement_str) query_statement (i->second.name, i->second.decl_file, - q->line, &(i->second.die), addr, q); + q->line[0], &(i->second.die), addr, q); else query_inline_instance_info (i->first, i->second, q); } @@ -3390,7 +3429,7 @@ query_dwarf_func (Dwarf_Die * func, void * arg) Dwarf_Die d; q->dw.function_die (&d); - if (q->dw.die_has_pc (&d, query_addr)) + if (q->dw.die_has_pc (d, query_addr)) record_this_function = true; } @@ -3476,7 +3515,24 @@ query_cu (Dwarf_Die * cudie, void * arg) if (q->filtered_srcfiles.empty()) return DWARF_CB_OK; } - + // Verify that a raw address matches the beginning of a + // statement. This is a somewhat lame check that the address + // is at the start of an assembly instruction. + if (q->has_statement_num) + { + Dwarf_Addr queryaddr = q->statement_num_val; + dwarf_line_t address_line(dwarf_getsrc_die(cudie, queryaddr)); + Dwarf_Addr lineaddr = 0; + if (address_line) + lineaddr = address_line.addr(); + if (!address_line || lineaddr != queryaddr) + { + stringstream msg; + msg << "address 0x" << hex << queryaddr + << "does not match the begining of a statement"; + throw semantic_error(msg.str()); + } + } // Pick up [entrypc, name, DIE] tuples for all the functions // matching the query, and fill in the prologue endings of them // all in a single pass. @@ -3497,18 +3553,18 @@ query_cu (Dwarf_Die * cudie, void * arg) for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin(); i != q->filtered_srcfiles.end(); ++i) q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str, - query_srcfile_line, q); + q->line_type, query_srcfile_line, q); } else { // Otherwise, simply probe all resolved functions. - for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); + for (func_info_map_t::iterator i = q->filtered_functions.begin(); i != q->filtered_functions.end(); ++i) query_func_info (i->first, i->second, q); // And all inline instances (if we're not excluding inlines with ".call") if (! q->has_call) - for (map<Dwarf_Addr, inline_instance_info>::iterator i + for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) query_inline_instance_info (i->first, i->second, q); } @@ -3576,7 +3632,7 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q) GElf_Ehdr ehdr_mem; GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem); - if (em == 0) { q->dw.dwfl_assert ("dwfl_getehdr", dwfl_errno()); } + if (em == 0) { dwfl_assert ("dwfl_getehdr", dwfl_errno()); } int elf_machine = em->e_machine; const char* debug_filename = ""; const char* main_filename = ""; @@ -3681,8 +3737,8 @@ dwflpp::query_modules(dwarf_query *q) { cache_modules_dwarf(); - map<string, module_info*>::iterator i = module_cache.cache.find(name); - if (i != module_cache.cache.end()) + map<string, module_info*>::iterator i = sess.module_cache->cache.find(name); + if (i != sess.module_cache->cache.end()) { module_info *mi = i->second; query_module(mi->mod, mi, name.c_str(), mi->addr, q); @@ -4621,7 +4677,7 @@ void dwarf_builder::build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { // NB: the kernel/user dwlfpp objects are long-lived. @@ -4697,12 +4753,18 @@ symbol_table::~symbol_table() } void -symbol_table::add_symbol(const char *name, Dwarf_Addr addr, - Dwarf_Addr *high_addr) +symbol_table::add_symbol(const char *name, bool weak, Dwarf_Addr addr, + Dwarf_Addr *high_addr) { +#ifdef __powerpc__ + // Map ".sys_foo" to "sys_foo". + if (name[0] == '.') + name++; +#endif func_info *fi = new func_info(); fi->addr = addr; fi->name = name; + fi->weak = weak; map_by_name[fi->name] = fi; // TODO: Use a multimap in case there are multiple static // functions with the same name? @@ -4753,8 +4815,8 @@ symbol_table::read_symbols(FILE *f, const string& path) free(mod); goto done; } - if (type == 'T' || type == 't') - add_symbol(name, (Dwarf_Addr) addr, &high_addr); + if (type == 'T' || type == 't' || type == 'W') + add_symbol(name, (type == 'W'), (Dwarf_Addr) addr, &high_addr); free(name); } @@ -4809,6 +4871,55 @@ symbol_table::read_from_text_file(const string& path) return status; } +void +symbol_table::prepare_section_rejection(Dwfl_Module *mod) +{ +#ifdef __powerpc__ + /* + * The .opd section contains function descriptors that can look + * just like function entry points. For example, there's a function + * descriptor called "do_exit" that links to the entry point ".do_exit". + * Reject all symbols in .opd. + */ + opd_section = SHN_UNDEF; + Dwarf_Addr bias; + Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias)) + ?: dwfl_module_getelf (mod, &bias)); + Elf_Scn* scn = 0; + size_t shstrndx; + + if (!elf) + return; + if (elf_getshstrndx(elf, &shstrndx) != 0) + return; + while ((scn = elf_nextscn(elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem); + if (!shdr) + continue; + const char *name = elf_strptr(elf, shstrndx, shdr->sh_name); + if (!strcmp(name, ".opd")) + { + opd_section = elf_ndxscn(scn); + return; + } + } +#endif +} + +bool +symbol_table::reject_section(GElf_Word section) +{ + if (section == SHN_UNDEF) + return true; +#ifdef __powerpc__ + if (section == opd_section) + return true; +#endif + return false; +} + enum info_status symbol_table::get_from_elf() { @@ -4816,12 +4927,16 @@ symbol_table::get_from_elf() Dwfl_Module *mod = mod_info->mod; int syments = dwfl_module_getsymtab(mod); assert(syments); + prepare_section_rejection(mod); for (int i = 1; i < syments; ++i) { GElf_Sym sym; - const char *name = dwfl_module_getsym(mod, i, &sym, NULL); - if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC) - add_symbol(name, sym.st_value, &high_addr); + GElf_Word section; + const char *name = dwfl_module_getsym(mod, i, &sym, §ion); + if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC && + !reject_section(section)) + add_symbol(name, (GELF_ST_BIND(sym.st_info) == STB_WEAK), + sym.st_value, &high_addr); } return info_present; } @@ -4913,6 +5028,33 @@ symbol_table::lookup_symbol_address(const string& name) return 0; } +// This is the kernel symbol table. The kernel macro cond_syscall creates +// a weak symbol for each system call and maps it to sys_ni_syscall. +// For system calls not implemented elsewhere, this weak symbol shows up +// in the kernel symbol table. Following the precedent of dwarfful stap, +// we refuse to consider such symbols. Here we delete them from our +// symbol table. +// TODO: Consider generalizing this and/or making it part of blacklist +// processing. +void +symbol_table::purge_syscall_stubs() +{ + Dwarf_Addr stub_addr = lookup_symbol_address("sys_ni_syscall"); + if (stub_addr == 0) + return; + for (size_t i = 0; i < list_by_addr.size(); i++) + { + func_info *fi = list_by_addr.at(i); + if (fi->weak && fi->addr == stub_addr && fi->name != "sys_ni_syscall") + { + list_by_addr.erase(list_by_addr.begin()+i); + map_by_name.erase(fi->name); + delete fi; + i--; + } + } +} + void module_info::get_symtab(dwarf_query *q) { @@ -4968,6 +5110,9 @@ module_info::get_symtab(dwarf_query *q) // precedes the call to query_module_symtab(). So we should never read // a module's symbol table without first having tried to get its dwarf. sym_table->mark_dwarf_redundancies(&q->dw); + + if (name == TOK_KERNEL) + sym_table->purge_syscall_stubs(); } module_info::~module_info() @@ -5052,25 +5197,19 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s) // utrace user-space probes // ------------------------------------------------------------------------ -// Since we don't have access to <linux/utrace.h>, we'll have to -// define our own version of the UTRACE_EVENT flags. +static string TOK_THREAD("thread"); +static string TOK_SYSCALL("syscall"); + +// Note that these flags don't match up exactly with UTRACE_EVENT +// flags (and that's OK). enum utrace_derived_probe_flags { UDPF_NONE, - UDPF_QUIESCE, // UTRACE_EVENT(QUIESCE) - UDPF_REAP, // UTRACE_EVENT(REAP) - UDPF_CLONE, // UTRACE_EVENT(CLONE) - UDPF_VFORK_DONE, // UTRACE_EVENT(VFORK_DONE) - UDPF_EXEC, // UTRACE_EVENT(EXEC) - UDPF_EXIT, // UTRACE_EVENT(EXIT) - UDPF_DEATH, // UTRACE_EVENT(DEATH) - UDPF_SYSCALL_ENTRY, // UTRACE_EVENT(SYSCALL_ENTRY) - UDPF_SYSCALL_EXIT, // UTRACE_EVENT(SYSCALL_EXIT) - UDPF_SIGNAL, // UTRACE_EVENT(SIGNAL) - UDPF_SIGNAL_IGN, // UTRACE_EVENT(SIGNAL_IGN) - UDPF_SIGNAL_STOP, // UTRACE_EVENT(SIGNAL_STOP) - UDPF_SIGNAL_TERM, // UTRACE_EVENT(SIGNAL_TERM) - UDPF_SIGNAL_CORE, // UTRACE_EVENT(SIGNAL_CORE) - UDPF_JCTL, // UTRACE_EVENT(JCTL) + UDPF_BEGIN, // process begin + UDPF_END, // process end + UDPF_THREAD_BEGIN, // thread begin + UDPF_THREAD_END, // thread end + UDPF_SYSCALL, // syscall entry + UDPF_SYSCALL_RETURN, // syscall exit UDPF_NFLAGS }; @@ -5100,6 +5239,9 @@ private: bool flags_seen[UDPF_NFLAGS]; void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p); + void emit_vm_callback_probe_decl (systemtap_session& s, bool has_path, + string path, int64_t pid, + string vm_callback); public: utrace_derived_probe_group(): num_probes(0), flags_seen() { } @@ -5144,15 +5286,9 @@ void utrace_derived_probe::join_group (systemtap_session& s) { if (! s.utrace_derived_probes) - { + { s.utrace_derived_probes = new utrace_derived_probe_group (); - - // Make sure <linux/tracehook.h> is included early. - embeddedcode *ec = new embeddedcode; - ec->tok = NULL; - ec->code = string("#include <linux/tracehook.h>\n"); - s.embeds.push_back(ec); - } + } s.utrace_derived_probes->enroll (this); task_finder_derived_probe_group::create_session_group (s); @@ -5164,7 +5300,7 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) { assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - if (flags != UDPF_SYSCALL_ENTRY && flags != UDPF_SYSCALL_EXIT) + if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN) throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols", e->tok); @@ -5198,28 +5334,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) // Remember that we've seen a target variable. target_symbol_seen = true; - // Synthesize a function. - functiondecl *fdecl = new functiondecl; - fdecl->tok = e->tok; - embeddedcode *ec = new embeddedcode; - ec->tok = e->tok; - - string fname = (string("_utrace_syscall_get") + "_" - + lex_cast<string>(tick++)); - string locvalue = "CONTEXT->data"; - - ec->code = string("THIS->__retvalue = *tracehook_syscall_callno(CONTEXT->regs); /* pure */"); - - fdecl->name = fname; - fdecl->body = ec; - fdecl->type = pe_long; - - sess.functions.push_back(fdecl); - - // Synthesize a functioncall. + // We're going to substitute a synthesized 'syscall_nr' function + // call for the '$syscall' reference. functioncall* n = new functioncall; n->tok = e->tok; - n->function = fname; + n->function = "syscall_nr"; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session provide <functioncall*> (this, n); @@ -5232,7 +5351,7 @@ struct utrace_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { string path; @@ -5243,19 +5362,24 @@ struct utrace_builder: public derived_probe_builder enum utrace_derived_probe_flags flags = UDPF_NONE; assert (has_path || has_pid); - if (has_null_param (parameters, "death")) - flags = UDPF_DEATH; - else if (has_null_param (parameters, "syscall")) + if (has_null_param (parameters, TOK_THREAD)) + { + if (has_null_param (parameters, TOK_BEGIN)) + flags = UDPF_THREAD_BEGIN; + else if (has_null_param (parameters, TOK_END)) + flags = UDPF_THREAD_END; + } + else if (has_null_param (parameters, TOK_SYSCALL)) { if (has_null_param (parameters, TOK_RETURN)) - flags = UDPF_SYSCALL_EXIT; + flags = UDPF_SYSCALL_RETURN; else - flags = UDPF_SYSCALL_ENTRY; + flags = UDPF_SYSCALL; } - else if (has_null_param (parameters, "clone")) - flags = UDPF_CLONE; - else if (has_null_param (parameters, "exec")) - flags = UDPF_EXEC; + else if (has_null_param (parameters, TOK_BEGIN)) + flags = UDPF_BEGIN; + else if (has_null_param (parameters, TOK_END)) + flags = UDPF_END; // If we have a path, we need to validate it. if (has_path) @@ -5338,6 +5462,7 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s, } s.op->line() << " .callback=&_stp_utrace_probe_cb,"; + s.op->line() << " .vm_callback=NULL,"; s.op->line() << " },"; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; s.op->line() << " .ph=&" << p->name << ","; @@ -5345,29 +5470,46 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s, // Handle flags switch (p->flags) { - case UDPF_CLONE: - s.op->line() << " .ops={ .report_clone=stap_utrace_probe_clone, .report_death=stap_utrace_task_finder_report_death },"; - s.op->line() << " .flags=(UTRACE_EVENT(CLONE)|UTRACE_EVENT(DEATH)),"; + // Look in _stp_utrace_probe_cb for description of why quiesce is + // used here. + case UDPF_BEGIN: // process begin + s.op->line() << " .flags=(UDPF_BEGIN),"; + s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },"; + s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),"; break; - case UDPF_EXEC: - // Notice we're not setting up a .ops/.report_exec handler here. - // Instead, we'll just call the probe directly when we get - // notified the exec happened. - s.op->line() << " .flags=(UTRACE_EVENT(EXEC)),"; + case UDPF_THREAD_BEGIN: // thread begin + s.op->line() << " .flags=(UDPF_THREAD_BEGIN),"; + s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },"; + s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),"; break; - case UDPF_DEATH: - // Notice we're not setting up a .ops/.report_death handler - // here. Instead, we'll just call the probe directly when we - // get notified the death happened. - s.op->line() << " .flags=(UTRACE_EVENT(DEATH)),"; + + // Notice we're not setting up a .ops/.report_death handler for + // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call + // the probe directly when we get notified. + case UDPF_END: // process end + s.op->line() << " .flags=(UDPF_END),"; break; - case UDPF_SYSCALL_ENTRY: + case UDPF_THREAD_END: // thread end + s.op->line() << " .flags=(UDPF_THREAD_END),"; + break; + + // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death + // handler isn't strictly necessary. However, it helps to keep + // our attaches/detaches symmetrical. + case UDPF_SYSCALL: + s.op->line() << " .flags=(UDPF_SYSCALL),"; s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },"; - s.op->line() << " .flags=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),"; + s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),"; break; - case UDPF_SYSCALL_EXIT: + case UDPF_SYSCALL_RETURN: + s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),"; s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },"; - s.op->line() << " .flags=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),"; + s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),"; + break; + case UDPF_NONE: + s.op->line() << " .flags=(UDPF_NONE),"; + s.op->line() << " .ops={ },"; + s.op->line() << " .events=0,"; break; default: throw semantic_error ("bad utrace probe flag"); @@ -5379,6 +5521,40 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s, void +utrace_derived_probe_group::emit_vm_callback_probe_decl (systemtap_session& s, + bool has_path, + string path, + int64_t pid, + string vm_callback) +{ + s.op->newline() << "{"; + s.op->line() << " .tgt={"; + + if (has_path) + { + s.op->line() << " .pathname=\"" << path << "\","; + s.op->line() << " .pid=0,"; + } + else + { + s.op->line() << " .pathname=NULL,"; + s.op->line() << " .pid=" << pid << ","; + } + + s.op->line() << " .callback=NULL,"; + s.op->line() << " .vm_callback=&" << vm_callback << ","; + s.op->line() << " },"; + s.op->line() << " .pp=\"internal\","; + s.op->line() << " .ph=NULL,"; + s.op->line() << " .flags=(UDPF_NONE),"; + s.op->line() << " .ops={ NULL },"; + s.op->line() << " .events=0,"; + s.op->line() << " .engine_attached=0,"; + s.op->line() << " },"; +} + + +void utrace_derived_probe_group::emit_module_decls (systemtap_session& s) { if (probes_by_path.empty() && probes_by_pid.empty()) @@ -5386,20 +5562,34 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "/* ---- utrace probes ---- */"; + s.op->newline() << "enum utrace_derived_probe_flags {"; + s.op->indent(1); + s.op->newline() << "UDPF_NONE,"; + s.op->newline() << "UDPF_BEGIN,"; + s.op->newline() << "UDPF_END,"; + s.op->newline() << "UDPF_THREAD_BEGIN,"; + s.op->newline() << "UDPF_THREAD_END,"; + s.op->newline() << "UDPF_SYSCALL,"; + s.op->newline() << "UDPF_SYSCALL_RETURN,"; + s.op->newline() << "UDPF_NFLAGS"; + s.op->newline(-1) << "};"; + s.op->newline() << "struct stap_utrace_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() << "enum utrace_derived_probe_flags flags;"; s.op->newline() << "struct utrace_engine_ops ops;"; - s.op->newline() << "unsigned long flags;"; + s.op->newline() << "unsigned long events;"; s.op->newline() << "int engine_attached;"; s.op->newline(-1) << "};"; - // Output handler function for CLONE events - if (flags_seen[UDPF_CLONE]) + + // Output handler function for UDPF_BEGIN and UDPF_THREAD_BEGIN + if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]) { - s.op->newline() << "static u32 stap_utrace_probe_clone(struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) {"; + s.op->newline() << "static u32 stap_utrace_probe_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) {"; s.op->indent(1); s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;"; @@ -5410,12 +5600,15 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "(*p->ph) (c);"; common_probe_entryfn_epilogue (s.op); - s.op->newline() << "return UTRACE_ACTION_RESUME;"; + // UTRACE_ACTION_NEWSTATE not needed here to clear quiesce since + // we're detaching - utrace automatically restarts the thread. + s.op->newline() << "debug_task_finder_detach();"; + s.op->newline() << "return UTRACE_ACTION_DETACH;"; s.op->newline(-1) << "}"; } - // Output handler function for EXEC and DEATH events - if (flags_seen[UDPF_EXEC] || flags_seen[UDPF_DEATH]) + // Output handler function for UDPF_END and UDPF_THREAD_END + if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END]) { s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {"; s.op->indent(1); @@ -5432,7 +5625,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) } // Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events - if (flags_seen[UDPF_SYSCALL_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT]) + if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) { s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {"; s.op->indent(1); @@ -5450,9 +5643,9 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; } - // Output task finder callback routine that gets called for all + // Output task_finder callback routine that gets called for all // utrace probe types. - s.op->newline() << "static int _stp_utrace_probe_cb(struct task_struct *tsk, int register_p, struct stap_task_finder_target *tgt) {"; + s.op->newline() << "static int _stp_utrace_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_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);"; @@ -5463,74 +5656,135 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "switch (p->flags) {"; s.op->indent(1); - // When registering an exec probe, we can't install a utrace engine, - // since we're already in a exec event. So, we just call the probe - // directly. Note that for existing threads, this won't really work - // since our state isn't STAP_SESSION_RUNNING yet. But that's OK, - // since this isn't really a 'exec' event - it is a notification - // that task_finder found an interesting process. - if (flags_seen[UDPF_EXEC]) - { - s.op->newline() << "case UTRACE_EVENT(EXEC):"; + + // When receiving a UTRACE_EVENT(CLONE) event, we can't call the + // begin/thread.begin probe directly. So, we'll just attach an + // engine that waits for the thread to quiesce. When the thread + // quiesces, then call the probe. + if (flags_seen[UDPF_BEGIN]) + { + s.op->newline() << "case UDPF_BEGIN:"; s.op->indent(1); - s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; - s.op->newline() << "break;"; - s.op->indent(-1); - } - // For death probes, do nothing at registration time. We'll handle - // these in the 'register_p == 0' case. - if (flags_seen[UDPF_DEATH]) - { - s.op->newline() << "case UTRACE_EVENT(DEATH):"; + s.op->newline() << "if (process_p) {"; + s.op->indent(1); + s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);"; + s.op->newline() << "if (rc == 0) {"; s.op->indent(1); + s.op->newline() << "p->engine_attached = 1;"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; s.op->newline() << "break;"; s.op->indent(-1); - } - // Attach an engine for CLONE, SYSCALL_ENTRY, and SYSCALL_EXIT events. - if (flags_seen[UDPF_CLONE] || flags_seen[UDPF_SYSCALL_ENTRY] - || flags_seen[UDPF_SYSCALL_EXIT]) - { - s.op->newline() << "case (UTRACE_EVENT(CLONE)|UTRACE_EVENT(DEATH)):"; - s.op->newline() << "case (UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)):"; - s.op->newline() << "case (UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)):"; + } + if (flags_seen[UDPF_THREAD_BEGIN]) + { + s.op->newline() << "case UDPF_THREAD_BEGIN:"; s.op->indent(1); - s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE, &p->ops, p);"; - s.op->newline() << "if (IS_ERR(engine)) {"; + s.op->newline() << "if (! process_p) {"; s.op->indent(1); - s.op->newline() << "int error = -PTR_ERR(engine);"; - s.op->newline() << "if (error != ENOENT) {"; + s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);"; + s.op->newline() << "if (rc == 0) {"; s.op->indent(1); - s.op->newline() << "_stp_error(\"utrace_attach returned error %d on pid %d\", error, (int)tsk->pid);"; - s.op->newline() << "rc = error;"; + s.op->newline() << "p->engine_attached = 1;"; s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; - s.op->newline() << "else if (unlikely(engine == NULL)) {"; + s.op->newline() << "break;"; + s.op->indent(-1); + } + + // For end/thread_end probes, do nothing at registration time. + // We'll handle these in the 'register_p == 0' case. + if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END]) + { + s.op->newline() << "case UDPF_END:"; + s.op->newline() << "case UDPF_THREAD_END:"; s.op->indent(1); - s.op->newline() << "_stp_error(\"utrace_attach returned NULL on pid %d!\", (int)tsk->pid);"; - s.op->newline() << "rc = ENOENT;"; - s.op->newline(-1) << "}"; - s.op->newline() << "else {"; + s.op->newline() << "break;"; + s.op->indent(-1); + } + + // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events. + if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) + { + s.op->newline() << "case UDPF_SYSCALL:"; + s.op->newline() << "case UDPF_SYSCALL_RETURN:"; + s.op->indent(1); + s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);"; + s.op->newline() << "if (rc == 0) {"; s.op->indent(1); - s.op->newline() << "utrace_set_flags(tsk, engine, p->flags);"; s.op->newline() << "p->engine_attached = 1;"; s.op->newline(-1) << "}"; s.op->newline() << "break;"; s.op->indent(-1); } + + s.op->newline() << "default:"; + s.op->indent(1); + s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);"; + s.op->newline() << "break;"; + s.op->indent(-1); s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; + // Since this engine could be attached to multiple threads, don't - // cleanup here. We'll cleanup at module unload time. + // call stap_utrace_detach_ops() here. s.op->newline() << "else {"; s.op->indent(1); + s.op->newline() << "switch (p->flags) {"; + s.op->indent(1); // For death probes, go ahead and call the probe directly. - if (flags_seen[UDPF_DEATH]) + if (flags_seen[UDPF_END]) + { + s.op->newline() << "case UDPF_END:"; + s.op->indent(1); + s.op->newline() << "if (process_p) {"; + s.op->indent(1); + s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; + s.op->newline(-1) << "}"; + s.op->newline() << "break;"; + s.op->indent(-1); + } + if (flags_seen[UDPF_THREAD_END]) { - s.op->newline() << "if (p->flags == UTRACE_EVENT(DEATH)) {"; + s.op->newline() << "case UDPF_THREAD_END:"; + s.op->indent(1); + s.op->newline() << "if (! process_p) {"; s.op->indent(1); s.op->newline() << "stap_utrace_probe_handler(tsk, p);"; s.op->newline(-1) << "}"; + s.op->newline() << "break;"; + s.op->indent(-1); } + + // For begin/thread_begin probes, at deregistration time we'll try + // to detach. This will only be necessary if the new thread/process + // got killed before the probe got run in the UTRACE_EVENT(QUIESCE) + // handler. + if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN] + || flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) + { + s.op->newline() << "case UDPF_BEGIN:"; + s.op->newline() << "case UDPF_THREAD_BEGIN:"; + s.op->newline() << "case UDPF_SYSCALL:"; + s.op->newline() << "case UDPF_SYSCALL_RETURN:"; + s.op->indent(1); + s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_MATCH_OPS, &p->ops, 0);"; + s.op->newline() << "if (! IS_ERR(engine) && engine != NULL) {"; + s.op->indent(1); + s.op->newline() << "utrace_detach(tsk, engine);"; + s.op->newline() << "debug_task_finder_detach();"; + + s.op->newline(-1) << "}"; + s.op->newline() << "break;"; + s.op->indent(-1); + } + + s.op->newline() << "default:"; + s.op->indent(1); + s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);"; + s.op->newline() << "break;"; + s.op->indent(-1); + s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; s.op->newline() << "return rc;"; s.op->newline(-1) << "}"; @@ -5544,6 +5798,14 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) for (p_b_path_iterator it = probes_by_path.begin(); it != probes_by_path.end(); it++) { + // Emit a "fake" probe decl that is really a hook for to get + // our vm_callback called. + string path = it->first; + s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; + emit_vm_callback_probe_decl (s, true, path, (int64_t)0, + "__stp_tf_vm_cb"); + s.op->newline() << "#endif"; + for (unsigned i = 0; i < it->second.size(); i++) { utrace_derived_probe *p = it->second[i]; @@ -5558,6 +5820,13 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) for (p_b_pid_iterator it = probes_by_pid.begin(); it != probes_by_pid.end(); it++) { + // Emit a "fake" probe decl that is really a hook for to get + // our vm_callback called. + s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; + emit_vm_callback_probe_decl (s, false, NULL, it->first, + "__stp_tf_vm_cb"); + s.op->newline() << "#endif"; + for (unsigned i = 0; i < it->second.size(); i++) { utrace_derived_probe *p = it->second[i]; @@ -5667,7 +5936,7 @@ struct uprobe_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { int64_t process, address; @@ -5802,6 +6071,8 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) // ------------------------------------------------------------------------ +static string TOK_TIMER("timer"); + struct timer_derived_probe: public derived_probe { int64_t interval, randomize; @@ -5983,7 +6254,7 @@ struct profile_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const &, + literal_map_t const &, vector<derived_probe *> & finished_results) { finished_results.push_back(new profile_derived_probe(sess, base, location)); @@ -6090,6 +6361,10 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s) // ------------------------------------------------------------------------ +static string TOK_PROCFS("procfs"); +static string TOK_READ("read"); +static string TOK_WRITE("write"); + struct procfs_derived_probe: public derived_probe { string path; @@ -6496,7 +6771,7 @@ struct procfs_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results); }; @@ -6505,13 +6780,13 @@ void procfs_builder::build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { string path; - bool has_procfs = get_param(parameters, "procfs", path); - bool has_read = (parameters.find("read") != parameters.end()); - bool has_write = (parameters.find("write") != parameters.end()); + bool has_procfs = get_param(parameters, TOK_PROCFS, path); + bool has_read = (parameters.find(TOK_READ) != parameters.end()); + bool has_write = (parameters.find(TOK_WRITE) != parameters.end()); // If no procfs path, default to "command". The runtime will do // this for us, but if we don't do it here, we'll think the @@ -6568,6 +6843,8 @@ procfs_builder::build(systemtap_session & sess, // statically inserted macro-based derived probes // ------------------------------------------------------------------------ +static string TOK_MARK("mark"); +static string TOK_FORMAT("format"); struct mark_arg { @@ -6802,9 +7079,9 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s, { // create synthetic probe point name; preserve condition vector<probe_point::component*> comps; - comps.push_back (new probe_point::component ("kernel")); - comps.push_back (new probe_point::component ("mark", new literal_string (probe_name))); - comps.push_back (new probe_point::component ("format", new literal_string (probe_format))); + comps.push_back (new probe_point::component (TOK_KERNEL)); + comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name))); + comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format))); this->sole_location()->components = comps; // expand the marker format @@ -7161,7 +7438,7 @@ public: void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results); }; @@ -7170,13 +7447,13 @@ void mark_builder::build(systemtap_session & sess, probe * base, probe_point *loc, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { string mark_str_val; - bool has_mark_str = get_param (parameters, "mark", mark_str_val); + bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val); string mark_format_val; - bool has_mark_format = get_param (parameters, "format", mark_format_val); + bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val); assert (has_mark_str); (void) has_mark_str; @@ -7460,7 +7737,7 @@ struct timer_builder: public derived_probe_builder { virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results); static void register_patterns(match_node *root); @@ -7470,7 +7747,7 @@ void timer_builder::build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { int64_t period, rand=0; @@ -7538,7 +7815,7 @@ timer_builder::register_patterns(match_node *root) { derived_probe_builder *builder = new timer_builder(); - root = root->bind("timer"); + root = root->bind(TOK_TIMER); root->bind_num("s")->bind(builder); root->bind_num("s")->bind_num("randomize")->bind(builder); @@ -7682,7 +7959,7 @@ struct perfmon_builder: public derived_probe_builder virtual void build(systemtap_session & sess, probe * base, probe_point * location, - std::map<std::string, literal *> const & parameters, + literal_map_t const & parameters, vector<derived_probe *> & finished_results) { string event; @@ -7994,18 +8271,19 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o) void register_standard_tapsets(systemtap_session & s) { - s.pattern_root->bind("begin")->bind(new be_builder(BEGIN)); - s.pattern_root->bind_num("begin")->bind(new be_builder(BEGIN)); - s.pattern_root->bind("end")->bind(new be_builder(END)); - s.pattern_root->bind_num("end")->bind(new be_builder(END)); - s.pattern_root->bind("error")->bind(new be_builder(ERROR)); - s.pattern_root->bind_num("error")->bind(new be_builder(ERROR)); + s.pattern_root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN)); + s.pattern_root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN)); + s.pattern_root->bind(TOK_END)->bind(new be_builder(END)); + s.pattern_root->bind_num(TOK_END)->bind(new be_builder(END)); + s.pattern_root->bind(TOK_ERROR)->bind(new be_builder(ERROR)); + s.pattern_root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR)); - s.pattern_root->bind("never")->bind(new never_builder()); + s.pattern_root->bind(TOK_NEVER)->bind(new never_builder()); timer_builder::register_patterns(s.pattern_root); - s.pattern_root->bind("timer")->bind("profile")->bind(new profile_builder()); - s.pattern_root->bind("perfmon")->bind_str("counter")->bind(new perfmon_builder()); + s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder()); + s.pattern_root->bind("perfmon")->bind_str("counter") + ->bind(new perfmon_builder()); // dwarf-based kernel/module parts dwarf_derived_probe::register_patterns(s.pattern_root); @@ -8019,37 +8297,44 @@ register_standard_tapsets(systemtap_session & s) ->bind(new uprobe_builder ()); // utrace user-space probes - s.pattern_root->bind_str(TOK_PROCESS)->bind("clone") + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_BEGIN) ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind("clone") + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN) ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind("exec") + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END) ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind("exec") + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END) ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall") + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN) ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall") + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN) ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN) + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN) + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END) ->bind(new utrace_builder ()); - s.pattern_root->bind_str(TOK_PROCESS)->bind("death") + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL) ->bind(new utrace_builder ()); - s.pattern_root->bind_num(TOK_PROCESS)->bind("death") + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL) + ->bind(new utrace_builder ()); + s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) + ->bind(new utrace_builder ()); + s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN) ->bind(new utrace_builder ()); // marker-based parts - s.pattern_root->bind("kernel")->bind_str("mark")->bind(new mark_builder()); - s.pattern_root->bind("kernel")->bind_str("mark")->bind_str("format") + s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK) + ->bind(new mark_builder()); + s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT) ->bind(new mark_builder()); // procfs parts - s.pattern_root->bind("procfs")->bind("read")->bind(new procfs_builder()); - s.pattern_root->bind_str("procfs")->bind("read")->bind(new procfs_builder()); - s.pattern_root->bind("procfs")->bind("write")->bind(new procfs_builder()); - s.pattern_root->bind_str("procfs")->bind("write")->bind(new procfs_builder()); + s.pattern_root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(new procfs_builder()); + s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_READ) + ->bind(new procfs_builder()); + s.pattern_root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(new procfs_builder()); + s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_WRITE) + ->bind(new procfs_builder()); } diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 34a4e8d0..19b30bf1 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -1,4 +1,4 @@ -.systemtap +.systemtap-* site.exp systemtap.log systemtap.sum diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index fa6e4fad..4fda9c5f 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,111 @@ +2008-06-23 Stan Cox <scox@redhat.com> + + * systemtap.base/stmt_rel.stp: Added test for + kernel.statement("Func@File:*") + +2008-06-18 Josh Stone <joshua.i.stone@intel.com> + + * systemtap.base/optim_voidstmt.stp: Add tests for various statement + optimizations that we should now be eliding. + +2008-06-16 Frank Ch. Eigler <fche@elastic.org> + + * systemtap.base/warnings.exp: Adjust warning count again (me1 and + elide were formerly duplicated). + +2008-06-16 Stan Cox <scox@redhat.com> + + * systemtap.base/warnings.stp: Added PR 6611 warning tests. + * systemtap.base/warnings.exp: Reset warning count. + +2008-06-13 Frank Ch. Eigler <fche@elastic.org> + + * lib/stap_run.exp: Remove module/cache warning boilerplate. + +2008-06-11 Mark Wielaard <mwielaard@redhat.com> + + * systemtap.base/warnings.exp: Expect 11 warning plus 1 .ko output + line. + +2008-06-11 David Smith <dsmith@redhat.com> + + * systemtap.base/utrace_p5.exp: Made changes to work when not + configured in the src directory. + * systemtap.base/utrace_p5_multi.c: Made changes to work on x86_64 + systems. + + * systemtap.base/utrace_p5.exp: Added 'process().thread.begin' and + 'process().thread.end' tests. + * systemtap.base/utrace_p5_multi.c: Added multi-threaded test + program for utrace_p5.exp. + * .gitignore: Updated. + +2008-06-10 Stan Cox <scox@redhat.com> + + * systemtap.base/warnings.exp: Adjust for duplicate warning elimination. + +2008-06-10 Frank Ch. Eigler <fche@elastic.org> + + PR 6470. + * parseko/preprocess08.stp, ...08b.stp: Revised/new test. + * systemtap.base/cmd_parse.exp: Added some argv[] tests. + +2008-06-09 Stan Cox <scox@redhat.com> + + * systemtap.base/stmt_rel.stp: New test. + * systemtap.base/stmt_rel.exp: Likewise. + +2008-06-06 David Smith <dsmith@redhat.com> + + * systemtap.base/utrace_p4.exp: Updated for utrace probe changes. + * systemtap.base/utrace_p5.exp: Ditto. + +2008-06-03 Frank Ch. Eigler <fche@elastic.org> + + * systemtap.context/backtrace.tcl: Tolerate "(inexact)" backtraces. + +2008-05-30 Wenji Huang <wenji.huang@oracle.com> + + * systemtap.base/debugpath.exp: Add path for self-built kernel. + +2008-05-28 Josh Stone <joshua.i.stone@intel.com> + + PR 6529 + * systemtap.base/error_fn.*: New tests. + +2008-05-28 Mark Wielaard <mwielaard@redhat.com> + + * testsuite/Makefile.am (clean-local): Correct redirect of stderr. + (installcheck): Don't depend on clean. + +2008-05-28 Mark Wielaard <mwielaard@redhat.com> + + * lib/systemtap.exp (setup_systemtap_environment): Create user + based cache dir. + * systemtap.base/cache.exp: Likewise. + * Makefile.am (clean-local): Try to remove all .systemtap and + .cache_test dirs. + +2008-05-26 Frank Ch. Eigler <fche@elastic.org> + + * testsuite/stmtvars.exp: Tweaked matching regexps, tested on + f7, rhel5. + +2008-05-24 Frank Ch. Eigler <fche@elastic.org> + + * configure.ac (enable-dejazilla): Add option, default off. + * Makefile.am (*check): Send systemtap.sum to dejazilla if enabled$a + * execrc: New helper script for runtest rc overriding. + * configure, Makefile.in: Regenerated. + +2008-05-23 Frank Ch. Eigler <fche@elastic.org> + + * buildok/{nfs,rpc}-all-probes.stp: Suppress warnings from empty probe + bodies. + * systemtap.pass1-4/buidok.exp: Mark above as kfail due to bug #4413. + While there, also mark the process_test kfail for #1155, though even + it fails only sporadically. + 2008-05-21 Frank Ch. Eigler <fche@elastic.org> PR 6538 diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index edaaff3c..b66bb75f 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -3,20 +3,30 @@ AUTOMAKE_OPTIONS = dejagnu -# The stap symlink is to enable "#! stap" test scripts. all-local: @echo Run \"make check\" or \"make installcheck\". + @if test -n "$(DEJAZILLA)"; then echo Test results will be emailed to $(DEJAZILLA); fi clean-local: -rm -f ./stap site.exp systemtap.sum systemtap.log - -rm -rf .systemtap .cache_test 2>/dev/null + -rm -rf .systemtap* .cache_test* 2>/dev/null -installcheck-local: clean site.exp - $(MAKE) AM_RUNTESTFLAGS="--tool_opts install" check-DEJAGNU +DEJAZILLA=@dejazilla@ + +# automake's dejagnu library already runs check-DEJAGNU before check-local +# That's why we need to add "execrc" to $(RUNTEST) - to ensure that this +# subtarget gets run even if runtest per se exits with a failure. +check-local: + if test -n "$(DEJAZILLA)"; then mail $(DEJAZILLA) < systemtap.sum; fi + +# but installcheck does not follow an implicit check-DEJAGNU, go figure +installcheck: site.exp + -$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU RUNTESTFLAGS="$(RUNTESTFLAGS) --tool_opts install" + if test -n "$(DEJAZILLA)"; then mail $(DEJAZILLA) < systemtap.sum; fi SRCDIR = $(shell cd $(srcdir); pwd) -EXTRA_DIST = config lib systemtap \ +EXTRA_DIST = execrc config lib systemtap \ parseok parseko semok semko transok transko buildok buildok \ systemtap.syscall systemtap.stress systemtap.string \ systemtap.pass1-4 systemtap.samples systemtap.printf \ @@ -30,4 +40,6 @@ LD_LIBRARY_PATH=$(DESTDIR)$(libdir)/systemtap CRASH_LIBDIR=$(DESTDIR)$(libdir)/systemtap SYSTEMTAP_PATH=$(DESTDIR)$(bindir) -RUNTEST="env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" +RUNTESTDEFAULTFLAGS = --tool $$tool --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/Makefile.in b/testsuite/Makefile.in index 99acf141..c8b07bdc 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -49,8 +49,6 @@ CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = DEJATOOL = $(PACKAGE) -RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir -EXPECT = expect DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -107,6 +105,7 @@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ +dejazilla = @dejazilla@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -134,8 +133,9 @@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = dejagnu +DEJAZILLA = @dejazilla@ SRCDIR = $(shell cd $(srcdir); pwd) -EXTRA_DIST = config lib systemtap \ +EXTRA_DIST = execrc config lib systemtap \ parseok parseko semok semko transok transko buildok buildok \ systemtap.syscall systemtap.stress systemtap.string \ systemtap.pass1-4 systemtap.samples systemtap.printf \ @@ -149,7 +149,9 @@ SYSTEMTAP_TAPSET = $(DESTDIR)$(pkgdatadir)/tapset LD_LIBRARY_PATH = $(DESTDIR)$(libdir)/systemtap CRASH_LIBDIR = $(DESTDIR)$(libdir)/systemtap SYSTEMTAP_PATH = $(DESTDIR)$(bindir) -RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH runtest" +RUNTESTDEFAULTFLAGS = --tool $$tool --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" all: all-am .SUFFIXES: @@ -351,7 +353,7 @@ distcleancheck: distclean $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU + $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU check-local check: check-am all-am: Makefile all-local installdirs: @@ -362,8 +364,6 @@ uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ @@ -414,7 +414,7 @@ install-pdf: install-pdf-am install-ps: install-ps-am -installcheck-am: installcheck-local +installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) @@ -439,30 +439,38 @@ uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am all-local am--refresh check check-DEJAGNU check-am \ - clean clean-generic clean-local dist dist-all dist-bzip2 \ - dist-gzip dist-shar dist-tarZ dist-zip distcheck distclean \ - distclean-DEJAGNU distclean-generic distcleancheck distdir \ - distuninstallcheck dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installcheck-local \ + check-local clean clean-generic clean-local dist dist-all \ + dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \ + distclean distclean-DEJAGNU distclean-generic distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ uninstall-am -# The stap symlink is to enable "#! stap" test scripts. all-local: @echo Run \"make check\" or \"make installcheck\". + @if test -n "$(DEJAZILLA)"; then echo Test results will be emailed to $(DEJAZILLA); fi clean-local: -rm -f ./stap site.exp systemtap.sum systemtap.log - -rm -rf .systemtap .cache_test 2>/dev/null - -installcheck-local: clean site.exp - $(MAKE) AM_RUNTESTFLAGS="--tool_opts install" check-DEJAGNU + -rm -rf .systemtap* .cache_test* 2>/dev/null + +# automake's dejagnu library already runs check-DEJAGNU before check-local +# That's why we need to add "execrc" to $(RUNTEST) - to ensure that this +# subtarget gets run even if runtest per se exits with a failure. +check-local: + if test -n "$(DEJAZILLA)"; then mail $(DEJAZILLA) < systemtap.sum; fi + +# but installcheck does not follow an implicit check-DEJAGNU, go figure +installcheck: site.exp + -$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU RUNTESTFLAGS="$(RUNTESTFLAGS) --tool_opts install" + if test -n "$(DEJAZILLA)"; then mail $(DEJAZILLA) < systemtap.sum; fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/testsuite/buildok/nfs-all-probes.stp b/testsuite/buildok/nfs-all-probes.stp index fb492c8c..ebff3472 100755 --- a/testsuite/buildok/nfs-all-probes.stp +++ b/testsuite/buildok/nfs-all-probes.stp @@ -1,4 +1,4 @@ -#! stap -p4 +#! stap -wp4 // Tests if all probes in nfs.stp and nfs_proc.stp are resolvable. diff --git a/testsuite/buildok/rpc-all-probes.stp b/testsuite/buildok/rpc-all-probes.stp index 2ecc42c7..c85ff80b 100755 --- a/testsuite/buildok/rpc-all-probes.stp +++ b/testsuite/buildok/rpc-all-probes.stp @@ -1,4 +1,4 @@ -#! stap -p4 +#! stap -wp4 // Tests if all probes in rpc.stp are resolvable. diff --git a/testsuite/configure b/testsuite/configure index bd8237cb..93494726 100755 --- a/testsuite/configure +++ b/testsuite/configure @@ -640,6 +640,7 @@ am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT +dejazilla LIBOBJS LTLIBOBJS' ac_subst_files='' @@ -1223,6 +1224,11 @@ Optional Features: --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer + --enable-dejazilla[=EMAIL] + enable dejazilla support to automatically email test + results to a central public collection point + (default is disabled). Optional EMAIL overrides the + default email address. Report bugs to <systemtap@sources.redhat.com>. _ACEOF @@ -2160,6 +2166,22 @@ fi +# Check whether --enable-dejazilla was given. +if test "${enable_dejazilla+set}" = set; then + enableval=$enable_dejazilla; +fi + +case "$enable_dejazilla" in + no) dejazilla= ;; + yes) dejazilla=dejazilla@elastic.org ;; + *) dejazilla="$enable_dejazilla" ;; +esac +if test -n "$dejazilla"; then + { echo "$as_me:$LINENO: A \"make *check\" will email results to $dejazilla" >&5 +echo "$as_me: A \"make *check\" will email results to $dejazilla" >&6;} +fi + + ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF @@ -2861,11 +2883,12 @@ am__untar!$am__untar$ac_delim MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim MAINT!$MAINT$ac_delim +dejazilla!$dejazilla$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 64; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 65; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/testsuite/configure.ac b/testsuite/configure.ac index 70d01e96..0fd78fe7 100644 --- a/testsuite/configure.ac +++ b/testsuite/configure.ac @@ -8,5 +8,20 @@ AC_CONFIG_AUX_DIR(..) AM_INIT_AUTOMAKE([dejagnu foreign]) AM_MAINTAINER_MODE +AC_ARG_ENABLE([dejazilla], + AS_HELP_STRING([--enable-dejazilla@<:@=EMAIL@:>@], + [enable dejazilla support to automatically email test results to a + central public collection point (default is disabled). Optional + EMAIL overrides the default email address.])) +case "$enable_dejazilla" in + no) dejazilla= ;; + yes) dejazilla=dejazilla@elastic.org ;; + *) dejazilla="$enable_dejazilla" ;; +esac +if test -n "$dejazilla"; then + AC_MSG_NOTICE([A "make *check" will email results to $dejazilla]) +fi +AC_SUBST(dejazilla) + AC_CONFIG_FILES(Makefile) AC_OUTPUT diff --git a/testsuite/execrc b/testsuite/execrc new file mode 100755 index 00000000..deff87e7 --- /dev/null +++ b/testsuite/execrc @@ -0,0 +1,5 @@ +#! /bin/sh + +# Run given program, but return a successful rc anyway. +eval $@ +exit 0 diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index 42efa4f8..43964d8e 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -33,7 +33,6 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args } eval spawn $cmd 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} diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index d458e98f..0f6a69dd 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -38,8 +38,9 @@ proc setup_systemtap_environment {} { set env(SRCDIR) $srcdir/.. } - # Use a local systemtap directory and cache - set env(SYSTEMTAP_DIR) [exec pwd]/.systemtap + # Use a local systemtap directory and cache. Add user name so + # make check and sudo make check don't clobber each other. + set env(SYSTEMTAP_DIR) [exec pwd]/.systemtap-[exec whoami] # PATH, SYSTEMTAP_TAPSET, SYSTEMTAP_RUNTIME, LD_LIBRARY_PATH are already set. foreach var {PATH STAP SRCDIR SYSTEMTAP_TAPSET SYSTEMTAP_RUNTIME SYSTEMTAP_DIR LD_LIBRARY_PATH} { diff --git a/testsuite/parseko/preprocess08.stp b/testsuite/parseko/preprocess08.stp index 6665983d..ba0d68e2 100755 --- a/testsuite/parseko/preprocess08.stp +++ b/testsuite/parseko/preprocess08.stp @@ -1,4 +1,4 @@ #! stap -p1 -# missing "then" token -%( arch == "2.6" %? +# premature EOF during THEN tokens +%( 0 == 0 %? diff --git a/testsuite/parseko/preprocess08b.stp b/testsuite/parseko/preprocess08b.stp new file mode 100755 index 00000000..a9697c28 --- /dev/null +++ b/testsuite/parseko/preprocess08b.stp @@ -0,0 +1,4 @@ +#! stap -p1 + +# premature EOF during ELSE tokens +%( 0 == 1 %? %: diff --git a/testsuite/semok/syscall_return.stp b/testsuite/semok/syscall_return.stp new file mode 100755 index 00000000..9a0ca7c4 --- /dev/null +++ b/testsuite/semok/syscall_return.stp @@ -0,0 +1,4 @@ +#!/bin/sh +# Per bz6588, this should get through the semantic pass without warnings. +stap -p2 -e 'probe syscall.*.return { printf("%s returns %s\n", name, retstr) }' 2>&1 | grep -q WARNING && exit 1 +exit 0 diff --git a/testsuite/systemtap.base/cache.exp b/testsuite/systemtap.base/cache.exp index 26d7b0ef..f7ed2786 100644 --- a/testsuite/systemtap.base/cache.exp +++ b/testsuite/systemtap.base/cache.exp @@ -65,8 +65,9 @@ proc stap_compile { TEST_NAME flags script args } { } # Since we need a clean cache directory, we'll use a temporary -# systemtap directory and cache -set local_systemtap_dir [exec pwd]/.cache_test +# systemtap directory and cache (add user name so make check and +# sudo make installcheck don't clobber each others) +set local_systemtap_dir [exec pwd]/.cache_test-[exec whoami] exec /bin/rm -rf $local_systemtap_dir if [info exists env(SYSTEMTAP_DIR)] { set old_systemtap_dir $env(SYSTEMTAP_DIR) diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp index cbce0455..e33bfa85 100644 --- a/testsuite/systemtap.base/cmd_parse.exp +++ b/testsuite/systemtap.base/cmd_parse.exp @@ -84,3 +84,40 @@ expect { eof {fail "cmd_parse8: unexpected EOF"} } wait + +spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 1 +expect { + -timeout 60 + "1 1" { pass cmd_parse9 } + timeout { fail "cmd_parse9 timeout" } + eof { fail "cmd_parse9 eof" } +} +wait + +spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 5 a b c d +expect { + -timeout 60 + "5 d" { pass cmd_parse10 } + timeout { fail "cmd_parse10 timeout" } + eof { fail "cmd_parse10 eof" } +} +wait + +spawn stap -e {probe begin { printf("%d %s\n", argc, argv[$1]) exit() }} 10 a b c d +expect { + -timeout 60 + "5 " { pass cmd_parse11 } + timeout { fail "cmd_parse11 timeout" } + eof { fail "cmd_parse11 eof" } +} +wait + +spawn stap -e {probe begin { printf("%d %s\n", argc, argv[0]) exit() }} +expect { + -timeout 60 + "0 " { pass cmd_parse12 } + timeout { fail "cmd_parse12 timeout" } + eof { fail "cmd_parse12 eof" } +} +wait + diff --git a/testsuite/systemtap.base/debugpath.exp b/testsuite/systemtap.base/debugpath.exp index b0b12207..9c42295d 100644 --- a/testsuite/systemtap.base/debugpath.exp +++ b/testsuite/systemtap.base/debugpath.exp @@ -10,7 +10,8 @@ expect { wait set test "debugpath-good" -spawn env SYSTEMTAP_DEBUGINFO_PATH=:/usr/lib/debug stap -e "probe kernel.function(\"sys_open\") {}" -p2 +set uname [exec /bin/uname -r] +spawn env SYSTEMTAP_DEBUGINFO_PATH=/lib/modules/$uname/build stap -e "probe kernel.function(\"sys_open\") {}" -p2 expect { -re {kernel.function.*pc=} { pass $test } timeout { fail "$test (timeout2)" } diff --git a/testsuite/systemtap.base/error_fn.exp b/testsuite/systemtap.base/error_fn.exp new file mode 100644 index 00000000..c0de850f --- /dev/null +++ b/testsuite/systemtap.base/error_fn.exp @@ -0,0 +1,7 @@ +# check that errors in nested functions are not lost on return +# bugzilla 6529 + +set test "error_fn" + +stap_run $srcdir/$subdir/$test.stp no_load ".*synthetic error.*" + diff --git a/testsuite/systemtap.base/error_fn.stp b/testsuite/systemtap.base/error_fn.stp new file mode 100644 index 00000000..2e68026f --- /dev/null +++ b/testsuite/systemtap.base/error_fn.stp @@ -0,0 +1,17 @@ +probe begin { + println("systemtap starting probe") + println("systemtap ending probe") +} + +function generate_error:long() { + error("synthetic error") + return 1 +} + +function compute:long() { + return generate_error() +} + +probe end { + compute() +} diff --git a/testsuite/systemtap.base/optim_arridx.exp b/testsuite/systemtap.base/optim_arridx.exp index 0987dec6..f4308db5 100644 --- a/testsuite/systemtap.base/optim_arridx.exp +++ b/testsuite/systemtap.base/optim_arridx.exp @@ -9,7 +9,7 @@ arr3:long [long] fna:long (a:long) return a fnb:long (a:long, b:long) -return (a) + (b) +return ((a) + (b)) + (printf("")) exit:unknown () %{ atomic_set (&session_state, STAP_SESSION_STOPPING); diff --git a/testsuite/systemtap.base/optim_arridx.stp b/testsuite/systemtap.base/optim_arridx.stp index 20710c7f..3e4f8fd2 100644 --- a/testsuite/systemtap.base/optim_arridx.stp +++ b/testsuite/systemtap.base/optim_arridx.stp @@ -1,7 +1,7 @@ global arr1, arr2, arr3, elide_idx1, elide_global_a, elide_global_b function fna(a:long) {return a} -function fnb(a:long, b:long) {return a+b} +function fnb(a:long, b:long) {return a+b+printf("")} probe begin { // array indices diff --git a/testsuite/systemtap.base/optim_voidstmt.exp b/testsuite/systemtap.base/optim_voidstmt.exp new file mode 100644 index 00000000..186dabad --- /dev/null +++ b/testsuite/systemtap.base/optim_voidstmt.exp @@ -0,0 +1,5 @@ +# Make sure that optimization works with void statements + +set test "optim_voidstmt" + +stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string -g diff --git a/testsuite/systemtap.base/optim_voidstmt.stp b/testsuite/systemtap.base/optim_voidstmt.stp new file mode 100644 index 00000000..343f81b3 --- /dev/null +++ b/testsuite/systemtap.base/optim_voidstmt.stp @@ -0,0 +1,95 @@ +/* + * optim_voidstmt.stp + * + * Verify statement optimizations in void contexts. + */ + +/* The printfs here force it not to be pure. */ +function goodL() { printf(""); return 1 } +function goodS() { printf(""); return "1" } + +/* These two functions lie about being pure, so they should be optimized out. + * If they get called, you get an error, and the test fails. + */ +function badL:long() %{ /* pure */ CONTEXT->last_error = "NOSEE"; %} +function badS:string() %{ /* pure */ CONTEXT->last_error = "NOSEE"; %} + +function fn1(x) { return x } +function fn2(x, y) { return x * y } + +probe begin { + println("systemtap starting probe") +} + +probe end { + println("systemtap ending probe") + + // most of these wouldn't have been optimized before, because part of the + // expression has an apparant side-effect in the good* calls + + // unary numeric operators + (+(goodL() + badL())) + (-(goodL() + badL())) + (!(goodL() + badL())) + (~(goodL() + badL())) + + // binary numeric operators + goodL() * badL() + goodL() / badL() + goodL() % badL() + goodL() + badL() + goodL() - badL() + goodL() >> badL() + goodL() << badL() + goodL() & badL() + goodL() ^ badL() + goodL() | badL() + goodL() < badL() + goodL() > badL() + goodL() <= badL() + goodL() >= badL() + goodL() == badL() + goodL() != badL() + + // logical operators + goodL() && badL() + badL() && badL() + goodL() || badL() + badL() || badL() + + // ternary operator + goodL() ? badL() : goodL() + goodL() ? goodL() : badL() + badL() ? badL() : badL() + + // binary string operators + goodS() . badS() + goodS() < badS() + goodS() > badS() + goodS() <= badS() + goodS() >= badS() + goodS() == badS() + goodS() != badS() + + // string-printing + sprintf("%d\n", goodL() + badL()) + sprintf("%d %d %s %s\n", goodL(), badL(), goodS(), badS()) + + // function calls + fn1(badL() + goodL()) + fn2(badL(), goodL()) + + // something complex, but harmless enough that only + // the good* calls should survive + fn1(fn2(goodL() - strlen(badL() + badL() * badL() / strlen(goodS()) ? + badS() . badS() . sprint(badL()) + : sprint(badL(), badS())), + badL() < badL() || badS() == badS()) + + goodL() % strlen(goodS())) + + println("systemtap test success") +} + +probe never { + print(goodL(), badL(), goodS(), badS(), fn1(1), fn2(1, 1)) +} diff --git a/testsuite/systemtap.base/stmt_rel.exp b/testsuite/systemtap.base/stmt_rel.exp new file mode 100644 index 00000000..25156d9b --- /dev/null +++ b/testsuite/systemtap.base/stmt_rel.exp @@ -0,0 +1,9 @@ +# test integer limits. Set and print variables and print constants. + +set test "stmt_rel" +set ::result_string {PASS bio_init +PASS line number +PASS wildcard +} + +stap_run2 $srcdir/$subdir/$test.stp diff --git a/testsuite/systemtap.base/stmt_rel.stp b/testsuite/systemtap.base/stmt_rel.stp new file mode 100644 index 00000000..13066161 --- /dev/null +++ b/testsuite/systemtap.base/stmt_rel.stp @@ -0,0 +1,71 @@ +global stack2pp, stack2func, stack3pp, stack3func +global wildcardpp, wild_count + +probe kernel.statement("bio_init@fs/bio.c+2") { + # stack2 = tokenize(backtrace(), " ") + stack2func = probefunc() + stack2pp = pp() +} +probe kernel.statement("bio_init@fs/bio.c+3") { + # stack3 = tokenize(backtrace(), " " ) + stack3func = probefunc() + stack3pp = pp() +} + +probe kernel.statement("bio_put@fs/bio.c:*") { + line = tokenize(pp(),":") + line = tokenize("",":") + line = substr(line,0,strlen(line)-2) + wildcardpp[strtol(line,10)]++ + + if (wild_count++ <= 10) { + next + } + + stack2pp = tokenize(stack2pp,":") + stack2pp = tokenize("",":") + stack3pp = tokenize(stack3pp,":") + stack3pp = tokenize("",":") + + stack2line = strtol (substr(stack2pp,0,strlen(stack2pp)-2), 10) + stack3line = strtol (substr(stack3pp,0,strlen(stack3pp)-2), 10) + + # Did functions for both bio_init probes match? + if (stack2func == stack3func) { + printf ("PASS %s\n", stack2func) + } + else { + printf ("FAIL %s %s\n", stack2func, stack3func) + } + + # Was line # for bio_init probe +2 < line # for bio_init probe +3? + if ((stack2line + 1) == stack3line) { + printf ("PASS line number\n") + } + else { + printf ("FAIL line number %d %d\n", stack2line, stack3line) + } + + # This test does not take optimized code into account + # Was address for bio_init probe +2 < address for bio_init probe +3? + # if (stack2 < stack3) { + # printf ("PASS address\n") + # } + # else { + # printf ("FAIL address %s %s\n", stack2, stack3) + # } + + # Did wildcard probe hit at least 5 different statements? + foreach ([i] in wildcardpp) { + statement_count += 1 + } + if (statement_count >= 5) { + printf ("PASS wildcard\n") + } + else + { + printf ("FAIL wildcard %d\n", statement_count) + } + + exit() +} diff --git a/testsuite/systemtap.base/stmtvars.exp b/testsuite/systemtap.base/stmtvars.exp index 6e950ea0..822e0d7e 100644 --- a/testsuite/systemtap.base/stmtvars.exp +++ b/testsuite/systemtap.base/stmtvars.exp @@ -5,9 +5,8 @@ set pc 0 set vars "" spawn stap -e "probe kernel.function(\"sys_open\") {\$foo}" -p4 -vv -u expect { - -re {probe sys_open.*pc=(0x.*)\r\n} { set pc $expect_out(1,string); exp_continue } - -re {alternatives: ([^\r\n]*) identifier [^\r\n]*\r\n} { set vars $expect_out(1,string) - exp_continue } + -re {probe sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc $expect_out(1,string); exp_continue } + -re {alternatives: ([^\r\n]*)\): identifier [^\r\n]*\r\n} { set vars $expect_out(1,string); exp_continue } timeout { fail "$test (timeout)" } eof } @@ -19,9 +18,8 @@ set pc2 0 set vars2 "" spawn stap -e "probe kernel.statement($pc) {\$foo}" -p4 -vv -u expect { - -re {probe sys_open.*pc=(0x.*)\r\n} { set pc2 $expect_out(1,string); exp_continue } - -re {alternatives: ([^\r\n]*) identifier [^\r\n]*\r\n} { set vars2 $expect_out(1,string) - exp_continue } + -re {probe sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc2 $expect_out(1,string); exp_continue } + -re {alternatives: ([^\r\n]*)\): identifier [^\r\n]*\r\n} { set vars2 $expect_out(1,string); exp_continue } timeout { fail "$test (timeout)" } eof } diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp index eb6ea685..5544ee55 100644 --- a/testsuite/systemtap.base/utrace_p4.exp +++ b/testsuite/systemtap.base/utrace_p4.exp @@ -49,11 +49,12 @@ proc stap_compile { TEST_NAME compile script args } { # Initialize variables set utrace_support_found 0 -set clone_script {"probe process(\"/bin/ls\").clone { print(\"ls clone\") }"} -set death_script {"probe process(\"/bin/ls\").death { print(\"ls death\") }"} +set begin_script {"probe process(\"/bin/ls\").begin { print(\"ls begin\") }"} +set end_script {"probe process(\"/bin/ls\").end { print(\"ls end\") }"} set syscall_script {"probe process(\"/bin/ls\").syscall { printf(\"|%d\", \$syscall) }"} set syscall_return_script {"probe process(\"/bin/ls\").syscall.return { printf(\"|%d\", \$syscall) }"} -set exec_script {"probe process(\"/bin/ls\").exec { print(\"ls exec\") }"} +set thread_begin_script {"probe process(\"/bin/ls\").thread.begin { print(\"ls thread.begin\") }"} +set thread_end_script {"probe process(\"/bin/ls\").thread.end { print(\"ls thread.end\") }"} # Try to find utrace_attach symbol in /proc/kallsyms set path "/proc/kallsyms" @@ -69,16 +70,16 @@ set TEST_NAME "UTRACE_P4_01" if {$utrace_support_found == 0} { untested "$TEST_NAME : no kernel utrace support found" } else { - # Try compiling a clone script - stap_compile $TEST_NAME 1 $clone_script + # Try compiling a begin script + stap_compile $TEST_NAME 1 $begin_script } set TEST_NAME "UTRACE_P4_02" if {$utrace_support_found == 0} { untested "$TEST_NAME : no kernel utrace support found" } else { - # Try compiling a death script - stap_compile $TEST_NAME 1 $death_script + # Try compiling a end script + stap_compile $TEST_NAME 1 $end_script } set TEST_NAME "UTRACE_P4_03" @@ -101,6 +102,14 @@ set TEST_NAME "UTRACE_P4_05" if {$utrace_support_found == 0} { untested "$TEST_NAME : no kernel utrace support found" } else { - # Try compiling an exec script - stap_compile $TEST_NAME 1 $exec_script + # Try compiling an thread.begin script + stap_compile $TEST_NAME 1 $thread_begin_script +} + +set TEST_NAME "UTRACE_P4_06" +if {$utrace_support_found == 0} { + untested "$TEST_NAME : no kernel utrace support found" +} else { + # Try compiling an thread.end script + stap_compile $TEST_NAME 1 $thread_end_script } diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp index cbb867d1..fcd617fe 100644 --- a/testsuite/systemtap.base/utrace_p5.exp +++ b/testsuite/systemtap.base/utrace_p5.exp @@ -3,24 +3,27 @@ # Initialize variables set utrace_support_found 0 set exepath "[pwd]/cat_[pid]" +set multi_srcpath "$srcdir/systemtap.base/utrace_p5_multi.c" +set multi_exepath "[pwd]/utrace_p5_multi_[pid]" +set multi_flags "libs=-lpthread" -set death_script { - global death_probes_fired = 0 +set end_script { + global end_probes_fired = 0 probe begin { printf("systemtap starting probe\n") } - probe process("%s").death { death_probes_fired++ } + probe process("%s").end { end_probes_fired++ } probe end { printf("systemtap ending probe\n") - printf("deaths = %%d\n", death_probes_fired) } + printf("end probes = %%d\n", end_probes_fired) } } -set death_script_output "deaths = 1\r\n" +set end_script_output "end probes = 1\r\n" -set exec_script { - global exec_probes_fired = 0 +set begin_script { + global begin_probes_fired = 0 probe begin { printf("systemtap starting probe\n") } - probe process("%s").exec { exec_probes_fired++ } + probe process("%s").begin { begin_probes_fired++ } probe end { printf("systemtap ending probe\n") - printf("execs = %%d\n", exec_probes_fired) } + printf("begin probes = %%d\n", begin_probes_fired) } } -set exec_script_output "execs = 1\r\n" +set begin_script_output "begin probes = 1\r\n" set syscall_script { global syscall_probes_fired = 0 @@ -46,17 +49,29 @@ set syscall_return_script { } set syscall_return_script_output "syscall_returns = \\d+\r\n" -set clone_script { - global clone_probes_fired = 0 +set thread_begin_script { + global thread_begin_probes_fired = 0 probe begin { printf("systemtap starting probe\n") } - probe process(%d).clone { clone_probes_fired++ } + probe process("%s").thread.begin { thread_begin_probes_fired++ } probe end { printf("systemtap ending probe\n") - if (clone_probes_fired > 0) { - printf("clones = %%d\n", clone_probes_fired) + if (thread_begin_probes_fired > 0) { + printf("thread_begins = %%d\n", thread_begin_probes_fired) } } } -set clone_script_output "clones = \\d+\r\n" +set thread_begin_script_output "thread_begins = \\d+\r\n" + +set thread_end_script { + global thread_end_probes_fired = 0 + probe begin { printf("systemtap starting probe\n") } + probe process("%s").thread.end { thread_end_probes_fired++ } + probe end { printf("systemtap ending probe\n") + if (thread_end_probes_fired > 0) { + printf("thread_ends = %%d\n", thread_end_probes_fired) + } + } +} +set thread_end_script_output "thread_ends = \\d+\r\n" # Try to find utrace_attach symbol in /proc/kallsyms set path "/proc/kallsyms" @@ -86,14 +101,33 @@ proc run_cat_5_sec {} { return 0; } +# Compile our multi-threaded test program. +set res [target_compile $multi_srcpath $multi_exepath executable $multi_flags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "unable to compile $multi_srcpath" + return +} + +# "load" generation function for stap_run. It spawns our +# multi-threaded test program and waits for it to finish. +proc run_utrace_p5_multi {} { + global multi_exepath + + if {[catch {exec $multi_exepath} res]} { + verbose "unable to run $multi_exepath: $res" + } + return 0; +} + set TEST_NAME "UTRACE_P5_01" if {$utrace_support_found == 0} { untested "$TEST_NAME : no kernel utrace support found" } elseif {![installtest_p]} { untested "$TEST_NAME" } else { - set script [format $death_script $exepath] - stap_run $TEST_NAME run_cat_5_sec $death_script_output -e $script + set script [format $end_script $exepath] + stap_run $TEST_NAME run_cat_5_sec $end_script_output -e $script } set TEST_NAME "UTRACE_P5_02" @@ -102,8 +136,8 @@ if {$utrace_support_found == 0} { } elseif {![installtest_p]} { untested "$TEST_NAME" } else { - set script [format $exec_script $exepath] - stap_run $TEST_NAME run_cat_5_sec $exec_script_output -e $script + set script [format $begin_script $exepath] + stap_run $TEST_NAME run_cat_5_sec $begin_script_output -e $script } set TEST_NAME "UTRACE_P5_03" @@ -132,9 +166,21 @@ if {$utrace_support_found == 0} { } elseif {![installtest_p]} { untested "$TEST_NAME" } else { - set script [format $clone_script [pid]] - stap_run $TEST_NAME run_cat_5_sec $clone_script_output -e $script + set script [format $thread_begin_script $multi_exepath] + stap_run $TEST_NAME run_utrace_p5_multi $thread_begin_script_output \ + -e $script +} + +set TEST_NAME "UTRACE_P5_06" +if {$utrace_support_found == 0} { + untested "$TEST_NAME : no kernel utrace support found" +} elseif {![installtest_p]} { + untested "$TEST_NAME" +} else { + set script [format $thread_end_script $multi_exepath] + stap_run $TEST_NAME run_utrace_p5_multi $thread_end_script_output \ + -e $script } # Cleanup -exec rm -f $exepath +exec rm -f $exepath $multi_exepath diff --git a/testsuite/systemtap.base/utrace_p5_multi.c b/testsuite/systemtap.base/utrace_p5_multi.c new file mode 100644 index 00000000..153243d0 --- /dev/null +++ b/testsuite/systemtap.base/utrace_p5_multi.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +void *thread_function( void *ptr ); + +struct thread_data { + int tnum; +}; + +int +main() +{ + pthread_t thread1, thread2; + int iret1, iret2; + + /* Create independent threads each of which will execute function */ + struct thread_data t1 = { 1 }; + struct thread_data t2 = { 2 }; + iret1 = pthread_create(&thread1, NULL, thread_function, (void*) &t1); + iret2 = pthread_create(&thread2, NULL, thread_function, (void*) &t2); + + /* Wait till threads are complete before main continues. Unless we + * wait we run the risk of executing an exit which will terminate + * the process and all threads before the threads have + * completed. */ + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); + + printf("Thread 1 returns: %d\n", iret1); + printf("Thread 2 returns: %d\n", iret2); + exit(0); +} + +void *thread_function(void *ptr) +{ + struct thread_data *td = ptr; + if (td->tnum == 1) { + int fd = open("/dev/null", O_RDONLY); + close(fd); + } +} diff --git a/testsuite/systemtap.base/warnings.exp b/testsuite/systemtap.base/warnings.exp index 6cff723d..b56d7a98 100644 --- a/testsuite/systemtap.base/warnings.exp +++ b/testsuite/systemtap.base/warnings.exp @@ -9,7 +9,7 @@ expect { eof { } } wait -if {$ok == 22} { +if {$ok == 14} { pass $test } else { fail "$test ($ok)" diff --git a/testsuite/systemtap.base/warnings.stp b/testsuite/systemtap.base/warnings.stp index a2ac5afc..94ed57b3 100644 --- a/testsuite/systemtap.base/warnings.stp +++ b/testsuite/systemtap.base/warnings.stp @@ -1,4 +1,4 @@ -# PR 1119, 6538 +# PR 1119 global elide_me1 function elide_me2 () {} @@ -6,3 +6,12 @@ function foo:long () { elide_me3 = 1 } function bar() { print(elide+me1) ; ; ; } probe never { elide_me4 = 1; (elide_me5+5); print (foo()) } probe never { print(elide+me1) bar () } + +# PR 6611 + +probe probea = kernel.statement("bio_init@fs/bio.c:135") + { printf("%d", funca(2)); elide_me6="foo" } +probe probea { printf("%d", funcb(2,3)); printf("%s",var) } + +function funcb(a:long, b:long) {return a + b} +function funca(a:long) {a=b; elide_me7=1; return a} diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl index 6c8aee40..aaec4cb8 100644 --- a/testsuite/systemtap.context/backtrace.tcl +++ b/testsuite/systemtap.context/backtrace.tcl @@ -20,11 +20,11 @@ expect { incr m1 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m1 == 1} {incr m1} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m1 == 2} {incr m1} } } @@ -34,11 +34,11 @@ expect { incr m2 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m2 == 1} {incr m2} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m2 == 2} {incr m2} } } @@ -50,15 +50,15 @@ expect { incr m3 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m3 == 1} {incr m3} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m3 == 2} {incr m3} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m3 == 3} {incr m3} } } @@ -68,11 +68,11 @@ expect { incr m4 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m4 == 1} {incr m4} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m4 == 2} {incr m4} exp_continue } @@ -88,19 +88,19 @@ expect { incr m5 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m5 == 1} {incr m5} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m5 == 2} {incr m5} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m5 == 3} {incr m5} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m5 == 4} {incr m5} } } @@ -110,19 +110,19 @@ expect { incr m6 expect { -timeout 5 - -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m6 == 1} {incr m6} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m6 == 2} {incr m6} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m6 == 3} {incr m6} exp_continue } - -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} { + -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]( \(inexact\))?\r\n} { if {$m6 == 4} {incr m6} } } diff --git a/testsuite/systemtap.context/context.exp b/testsuite/systemtap.context/context.exp index 71201a58..010db445 100644 --- a/testsuite/systemtap.context/context.exp +++ b/testsuite/systemtap.context/context.exp @@ -1,4 +1,4 @@ -set testlist {backtrace args pid} +set testlist {backtrace args pid num_args} if {![installtest_p]} { foreach test $testlist { diff --git a/testsuite/systemtap.context/num_args.stp b/testsuite/systemtap.context/num_args.stp new file mode 100644 index 00000000..9f15bb01 --- /dev/null +++ b/testsuite/systemtap.context/num_args.stp @@ -0,0 +1,53 @@ +%( arch == "i386" %? global ir = "eax", lr = "eax" %) +%( arch == "i686" %? global ir = "eax", lr = "eax" %) +%( arch == "x86_64" %? global ir = "eax", lr = "rax" %) +%( arch == "ppc64" %? global ir = "r3", lr = "r3" %) + +probe module("systemtap_test_module2").function("yyy_int") { + printf("yyy_int %d %d %d\n", int_arg(1), int_arg(2), int_arg(3)) +} +probe module("systemtap_test_module2").function("yyy_int").return { + printf("yyy_int returns %d\n", register(ir)) +} +probe module("systemtap_test_module2").function("yyy_uint") { + printf("yyy_uint %d %d %d\n", uint_arg(1), uint_arg(2), uint_arg(3)) +} +probe module("systemtap_test_module2").function("yyy_uint").return { + printf("yyy_uint returns %d\n", u_register(ir)) +} +probe module("systemtap_test_module2").function("yyy_long") { + printf("yyy_long %d %d %d\n", long_arg(1), long_arg(2), long_arg(3)) +} +probe module("systemtap_test_module2").function("yyy_long").return { + printf("yyy_long returns %d\n", register(lr)) +} +probe module("systemtap_test_module2").function("yyy_int64") { +# On i386, kernel is built with -mregparm=3. The first arg occupies the +# first two registers. The 2nd arg is not split between the 3rd register +# and the stack, but rather passed entirely on the stack. + printf("yyy_int64 %d %d %d\n", +%( arch == "i386" %? s64_arg(1), s64_arg(4), s64_arg(6) +%: %( arch == "i686" %? s64_arg(1), s64_arg(4), s64_arg(6) + %: s64_arg(1), s64_arg(2), s64_arg(3) + %) +%) + ) +} +probe module("systemtap_test_module2").function("yyy_int64").return { + printf("yyy_int64 returns %d\n", register(ir)) +} +probe module("systemtap_test_module2").function("yyy_char") { + printf("yyy_char %1b %1b %1b\n", int_arg(1), int_arg(2), int_arg(3)) +} +probe module("systemtap_test_module2").function("yyy_char").return { + printf("yyy_char returns %1b\n", register(ir)) +} +probe module("systemtap_test_module2").function("yyy_str") { + printf("yyy_str %s-%s-%s\n", kernel_string(pointer_arg(1)), kernel_string(pointer_arg(2)), kernel_string(pointer_arg(3))) +} +probe module("systemtap_test_module2").function("yyy_str").return { + printf("yyy_str returns %s\n", kernel_string(register(lr))) +} +probe begin { + printf("READY\n") +} diff --git a/testsuite/systemtap.context/num_args.tcl b/testsuite/systemtap.context/num_args.tcl new file mode 100644 index 00000000..48e83f4d --- /dev/null +++ b/testsuite/systemtap.context/num_args.tcl @@ -0,0 +1,62 @@ +set arglists {{} {--kelf --ignore-dwarf}} +foreach arglist $arglists { +set tag [concat numeric $arglist] +eval spawn stap $arglist $srcdir/$subdir/num_args.stp +expect { + -timeout 240 + "READY" { + exec echo 1 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_int -1 200 300\r\nyyy_int returns 499\r\n" { + pass "integer function arguments -- $tag" + } + timeout {fail "integer function arguments -- $tag"} + } + exec echo 2 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_uint 4294967295 200 300\r\nyyy_uint returns 499\r\n" { + pass "unsigned function arguments -- $tag" + } + timeout {fail "unsigned function arguments -- $tag"} + } + exec echo 3 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_long -1 200 300\r\nyyy_long returns 499\r\n" { + pass "long function arguments -- $tag" + } + timeout {fail "long function arguments -- $tag"} + } + exec echo 4 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_int64 -1 200 300\r\nyyy_int64 returns 499\r\n" { + pass "int64 function arguments -- $tag" + } + timeout {fail "int64 function arguments -- $tag"} + } + exec echo 5 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_char a b c\r\nyyy_char returns Q\r\n" { + pass "char function arguments -- $tag" + } + timeout {fail "char function arguments -- $tag"} + } + exec echo 6 > /proc/stap_test_cmd + expect { + -timeout 5 + "yyy_str Hello-System-Tap\r\nyyy_str returns XYZZY\r\n" { + pass "string function arguments -- $tag" + } + timeout {fail "string function arguments -- $tag"} + } + } + eof {fail "function arguments -- $tag: unexpected timeout"} +} +exec kill -INT -[exp_pid] +close +wait +} diff --git a/testsuite/systemtap.examples/ChangeLog b/testsuite/systemtap.examples/ChangeLog index 743e7adf..b1c34347 100644 --- a/testsuite/systemtap.examples/ChangeLog +++ b/testsuite/systemtap.examples/ChangeLog @@ -1,3 +1,23 @@ +2008-06-20 William Cohen <wcohen@redhat.com> + + * traceio2.meta: Correct test_check and test_installcheck commands. + +2008-06-20 William Cohen <wcohen@redhat.com> + + * traceio2.stp, traceio2.meta: New. + +2008-06-18 William Cohen <wcohen@redhat.com> + + * sleepingBeauties.stp, sleepingBeauties.meta: New. + +2008-06-17 William Cohen <wcohen@redhat.com> + + * graphs.stp, graphs.meta: New. + +2008-06-12 William Cohen <wcohen@redhat.com> + + * thread-times.stp, thread-times.meta: New. + 2008-05-20 William Cohen <wcohen@redhat.com> * io_submit.stp, io_submit.meta: diff --git a/testsuite/systemtap.examples/graphs.meta b/testsuite/systemtap.examples/graphs.meta new file mode 100644 index 00000000..60a522b3 --- /dev/null +++ b/testsuite/systemtap.examples/graphs.meta @@ -0,0 +1,13 @@ +title: Graphing Disk and CPU Utilization +name: graphs.stp +version: 1.0 +author: anonymous +keywords: disk cpu use graph +subsystem: disk cpu +status: production +exit: user-controlled +output: plot data +scope: system-wide +description: The script tracks the disk and CPU utilization. The resulting output of the script can be piped into gnuplot to generate a graph of disk and CPU USE. +test_check: stap -p4 graphs.stp +test_installcheck: stap graphs.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/graphs.stp b/testsuite/systemtap.examples/graphs.stp new file mode 100644 index 00000000..0c8e3796 --- /dev/null +++ b/testsuite/systemtap.examples/graphs.stp @@ -0,0 +1,60 @@ +#! stap + +# ------------------------------------------------------------------------ +# data collection + +# disk I/O stats +probe begin { qnames["ioblock"] ++; qsq_start ("ioblock") } +probe ioblock.request { qs_wait ("ioblock") qs_run("ioblock") } +probe ioblock.end { qs_done ("ioblock") } + +# CPU utilization +probe begin { qnames["cpu"] ++; qsq_start ("cpu") } +probe scheduler.cpu_on { if (!idle) {qs_wait ("cpu") qs_run ("cpu") }} +probe scheduler.cpu_off { if (!idle) qs_done ("cpu") } + + +# ------------------------------------------------------------------------ +# utilization history tracking + +global N +probe begin { N = 50 } + +global qnames, util, histidx + +function qsq_util_reset(q) { + u=qsq_utilization (q, 100) + qsq_start (q) + return u +} + +probe timer.ms(100) { # collect utilization percentages frequently + histidx = (histidx + 1) % N # into circular buffer + foreach (q in qnames) + util[histidx,q] = qsq_util_reset(q) +} + + +# ------------------------------------------------------------------------ +# general gnuplot graphical report generation + +probe timer.ms(1000) { + # emit gnuplot command to display recent history + + printf ("set yrange [0:100]\n") + printf ("plot ") + foreach (q in qnames+) + { + if (++nq >= 2) printf (", ") + printf ("'-' title \"%s\" with lines", q) + } + printf ("\n") + + foreach (q in qnames+) { + for (i = (histidx + 1) % N; i != histidx; i = (i + 1) % N) + printf("%d\n", util[i,q]) + printf ("e\n") + } + + printf ("pause 1\n") +} diff --git a/testsuite/systemtap.examples/sleepingBeauties.meta b/testsuite/systemtap.examples/sleepingBeauties.meta new file mode 100644 index 00000000..95e08361 --- /dev/null +++ b/testsuite/systemtap.examples/sleepingBeauties.meta @@ -0,0 +1,13 @@ +title: Generating Backtraces of Threads Waiting for IO Operations +name: sleepingBeauties.stp +version: 1.0 +author: anonymous +keywords: io scheduler +subsystem: scheduler +status: production +exit: user-controlled +output: trace +scope: system-wide +description: The script monitor time threads spend waiting for IO operations (in "D" state) in the wait_for_completion function. If a thread spends over 10ms wall-clock time waiting, information is printed out describing the thread number and executable name. When slow the wait_for_completion function complete, backtraces for the long duration calls are printed out. +test_check: stap -p4 sleepingBeauties.stp +test_installcheck: stap sleepingBeauties.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/sleepingBeauties.stp b/testsuite/systemtap.examples/sleepingBeauties.stp new file mode 100644 index 00000000..64c563a3 --- /dev/null +++ b/testsuite/systemtap.examples/sleepingBeauties.stp @@ -0,0 +1,58 @@ +#! /usr/bin/stap + +function time () { return gettimeofday_ms() } +global time_name = "ms" +global boredom = 10 # in time units +global name, back, backtime, bored + +/* Note: the order that the probes are listed should not matter. + However, the following order for + probe kernel.function("wait_for_completion").return and + probe kernel.function("wait_for_completion").call + avoids have the kretprobe stuff in the backtrace. + for more information see: + http://sources.redhat.com/bugzilla/show_bug.cgi?id=6436 +*/ + + +probe kernel.function("wait_for_completion").return +{ + t=tid() + + if ([t] in bored) { + patience = time() - backtime[t] + printf ("thread %d (%s) bored for %d %s\n", + t, name[t], patience, time_name) + } + + delete bored[t] + delete back[t] + delete name[t] + delete backtime[t] +} + + +probe kernel.function("wait_for_completion").call +{ + t=tid() + back[t]=backtrace() + name[t]=execname() + backtime[t]=time() + delete bored[t] +} + + +probe timer.profile { + foreach (tid+ in back) { + if ([tid] in bored) continue + + patience = time() - backtime[tid] + if (patience >= boredom) { + printf ("thread %d (%s) impatient after %d %s\n", + tid, name[tid], patience, time_name) + print_stack (back[tid]) + printf ("\n") + bored[tid] = 1 # defer further reports to wakeup + } + } +} diff --git a/testsuite/systemtap.examples/thread-times.meta b/testsuite/systemtap.examples/thread-times.meta new file mode 100644 index 00000000..fcbf062e --- /dev/null +++ b/testsuite/systemtap.examples/thread-times.meta @@ -0,0 +1,13 @@ +title: Profile kernel functions +name: thread-times.stp +version: 1.0 +author: anonymous +keywords: profiling +subsystem: kernel +status: production +exit: user-controlled +output: sorted-list +scope: system-wide +description: The thread-times.stp script sets up time-based sampling. Every five seconds it prints out a sorted list with the top twenty processes with samples broken down into percentage total time spent in user-space and kernel-space. +test_check: stap -p4 thread-times.stp +test_installcheck: stap thread-times.stp -c "sleep 1" diff --git a/testsuite/systemtap.examples/thread-times.stp b/testsuite/systemtap.examples/thread-times.stp new file mode 100644 index 00000000..1aeb2037 --- /dev/null +++ b/testsuite/systemtap.examples/thread-times.stp @@ -0,0 +1,32 @@ +#! /usr/bin/stap + +probe timer.profile { + tid=tid() + if (!user_mode()) + kticks[tid] <<< 1 + else + uticks[tid] <<< 1 + ticks <<< 1 + tids[tid] <<< 1 +} + +global uticks, kticks, ticks + +global tids + +probe timer.s(5), end { + allticks = @count(ticks) + printf ("%5s %7s %7s (of %d ticks)\n", "tid", "%user", "%kernel", allticks) + foreach (tid in tids- limit 20) { + uscaled = @count(uticks[tid])*10000/allticks + kscaled = @count(kticks[tid])*10000/allticks + printf ("%5d %3d.%02d%% %3d.%02d%%\n", + tid, uscaled/100, uscaled%100, kscaled/100, kscaled%100) + } + printf("\n") + + delete uticks + delete kticks + delete ticks + delete tids +} diff --git a/testsuite/systemtap.examples/traceio2.meta b/testsuite/systemtap.examples/traceio2.meta new file mode 100644 index 00000000..e6bca1a9 --- /dev/null +++ b/testsuite/systemtap.examples/traceio2.meta @@ -0,0 +1,13 @@ +title: Watch I/O Activity on a Particular Device +name: traceio2.stp +version: 1.0 +author: Red Hat +keywords: io +subsystem: io +status: production +exit: user-controlled +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" diff --git a/testsuite/systemtap.examples/traceio2.stp b/testsuite/systemtap.examples/traceio2.stp new file mode 100644 index 00000000..656c38b3 --- /dev/null +++ b/testsuite/systemtap.examples/traceio2.stp @@ -0,0 +1,20 @@ +global device_of_interest + +probe begin { + /* The following is not the most efficient way to do this. + One could directly put the result of usrdev2kerndev() + into device_of_interest. However, want to test out + the other device functions */ + dev = usrdev2kerndev($1) + device_of_interest = MKDEV(MAJOR(dev), MINOR(dev)) +} + +probe kernel.function ("vfs_write"), + kernel.function ("vfs_read") +{ + dev_nr = $file->f_path->dentry->d_inode->i_sb->s_dev + + if (dev_nr == device_of_interest) + printf ("%s(%d) %s 0x%x\n", + execname(), pid(), probefunc(), dev_nr) +} diff --git a/testsuite/systemtap.pass1-4/buildok.exp b/testsuite/systemtap.pass1-4/buildok.exp index 07580550..08d50fb5 100644 --- a/testsuite/systemtap.pass1-4/buildok.exp +++ b/testsuite/systemtap.pass1-4/buildok.exp @@ -9,6 +9,9 @@ foreach file [lsort [glob -nocomplain $srcdir/$self/*.stp]] { buildok/twentysix.stp {setup_kfail 4105 *-*-*} buildok/twentyseven.stp {setup_kfail 4166 *-*-*} buildok/sched_test.stp {setup_kfail 1155 *-*-*} + buildok/process_test.stp {setup_kfail 1155 *-*-*} + buildok/rpc-all-probes.stp {setup_kfail 4413 *-*-*} + buildok/nfs-all-probes.stp {setup_kfail 4413 *-*-*} } if {$rc == 0} { pass $test } else { fail $test } } diff --git a/testsuite/systemtap.samples/profile.exp b/testsuite/systemtap.samples/profile.exp index 9ca9da15..87174d2c 100644 --- a/testsuite/systemtap.samples/profile.exp +++ b/testsuite/systemtap.samples/profile.exp @@ -12,4 +12,4 @@ expect { #FIXME does not handle case of hanging primes.stp correctly wait -if {$ok > 0} { pass "$test ($ok)" } { fail "$test" } +if {$ok > 0} { pass $test } { fail $test } diff --git a/translate.cxx b/translate.cxx index b1037fef..433b82be 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1,6 +1,6 @@ // translation pass // Copyright (C) 2005-2008 Red Hat Inc. -// Copyright (C) 2005-2007 Intel Corporation. +// Copyright (C) 2005-2008 Intel Corporation. // // 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 @@ -14,6 +14,7 @@ #include "session.h" #include "tapsets.h" #include "util.h" +#include "dwarf_wrappers.h" #include <cstdlib> #include <iostream> @@ -43,6 +44,7 @@ struct c_unparser: public unparser, public visitor functiondecl* current_function; unsigned tmpvar_counter; unsigned label_counter; + unsigned action_counter; bool probe_or_function_needs_deref_fault_handler; varuse_collecting_visitor vcv_needs_global_locks; @@ -110,7 +112,7 @@ struct c_unparser: public unparser, public visitor void collect_map_index_types(vector<vardecl* > const & vars, set< pair<vector<exp_type>, exp_type> > & types); - void visit_statement (statement* s, unsigned actions, bool stmtize); + void record_actions (unsigned actions, bool update=false); void visit_block (block* s); void visit_embeddedcode (embeddedcode* s); @@ -619,10 +621,10 @@ struct mapvar else throw semantic_error("adding a value of an unsupported map type"); - res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " + + res += "; if (unlikely(rc)) { c->last_error = \"Array overflow, check " + stringify(maxsize > 0 ? "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES") - + "\"; }"; + + "\"; goto out; }}"; return res; } @@ -640,10 +642,10 @@ struct mapvar else throw semantic_error("setting a value of an unsupported map type"); - res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " + + res += "; if (unlikely(rc)) { c->last_error = \"Array overflow, check " + stringify(maxsize > 0 ? "size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES") - + "\"; }"; + + "\"; goto out; }}"; return res; } @@ -870,9 +872,7 @@ c_unparser::emit_common_header () o->newline() << "const char *last_error;"; // NB: last_error is used as a health flag within a probe. // While it's 0, execution continues - // When it's "", current function or probe unwinds and returns early // When it's "something", probe code unwinds, _stp_error's, sets error state - // See c_unparser::visit_statement() o->newline() << "const char *last_stmt;"; o->newline() << "struct pt_regs *regs;"; o->newline() << "unsigned long *unwaddr;"; @@ -1087,27 +1087,18 @@ c_unparser::emit_module_init () // one may install the incorrect debuginfo or -devel RPM, and try to // run a probe compiled for a different version. Catch this early, // just in case modversions didn't. - o->newline() << "down_read (& uts_sem);"; o->newline() << "{"; - o->indent(1); + o->newline(1) << "const char* release = UTS_RELEASE;"; - // Args, linux 2.6.19+ did a switcheroo on system_utsname to utsname(). - o->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)"; - o->newline() << "const char* machine = utsname()->machine;"; - o->newline() << "const char* release = utsname()->release;"; - o->newline() << "#else"; - o->newline() << "const char* machine = system_utsname.machine;"; - o->newline() << "const char* release = system_utsname.release;"; - o->newline() << "#endif"; + // NB: This UTS_RELEASE compile-time macro directly checks only that + // the compile-time kbuild tree matches the compile-time debuginfo/etc. + // It does not check the run time kernel value. However, this is + // probably OK since the kbuild modversions system aims to prevent + // mismatches between kbuild and runtime versions at module-loading time. - o->newline() << "if (strcmp (machine, " - << lex_cast_qstring (session->architecture) << ")) {"; - o->newline(1) << "_stp_error (\"module machine mismatch (%s vs %s)\", " - << "machine, " - << lex_cast_qstring (session->architecture) - << ");"; - o->newline() << "rc = -EINVAL;"; - o->newline(-1) << "}"; + // o->newline() << "const char* machine = UTS_MACHINE;"; + // NB: We could compare UTS_MACHINE too, but on x86 it lies + // (UTS_MACHINE=i386, but uname -m is i686). Sheesh. o->newline() << "if (strcmp (release, " << lex_cast_qstring (session->kernel_release) << ")) {"; @@ -1118,8 +1109,9 @@ c_unparser::emit_module_init () o->newline() << "rc = -EINVAL;"; o->newline(-1) << "}"; + // XXX: perform buildid-based checking if able + o->newline(-1) << "}"; - o->newline() << "up_read (& uts_sem);"; o->newline() << "if (rc) goto out;"; o->newline() << "(void) probe_point;"; @@ -1315,9 +1307,8 @@ c_unparser::emit_module_exit () o->newline() << "struct stat_data *stats = _stp_stat_get (time_" << p->name << ", 0);"; - o->newline() << "const char *error;"; o->newline() << "if (stats->count) {"; - o->newline(1) << "int64_t avg = _stp_div64 (&error, stats->sum, stats->count);"; + o->newline(1) << "int64_t avg = _stp_div64 (NULL, stats->sum, stats->count);"; o->newline() << "_stp_printf (\"probe %s (%s), hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\","; o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);"; o->newline(-1) << "}"; @@ -1352,6 +1343,7 @@ c_unparser::emit_function (functiondecl* v) this->current_probe = 0; this->current_function = v; this->tmpvar_counter = 0; + this->action_counter = 0; o->newline() << "struct function_" << c_varname (v->name) << "_locals * " @@ -1400,26 +1392,21 @@ c_unparser::emit_function (functiondecl* v) this->current_function = 0; - o->newline(-1) << "out:"; - o->newline(1) << ";"; - - // Function prologue: this is why we redirect the "return" above. - // Decrement nesting level. - o->newline() << "c->nesting --;"; - // Reset last_error to NULL if it was set to "" by script-level return() - o->newline() << "if (c->last_error && ! c->last_error[0])"; - o->newline(1) << "c->last_error = 0;"; - o->indent(-1); + record_actions(0, true); 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(-1) << "out:"; + o->newline(1) << ";"; + + // Function prologue: this is why we redirect the "return" above. + // Decrement nesting level. + o->newline() << "c->nesting --;"; + o->newline() << "#undef CONTEXT"; o->newline() << "#undef THIS"; o->newline(-1) << "}\n"; @@ -1436,6 +1423,7 @@ c_unparser::emit_probe (derived_probe* v) this->current_function = 0; this->current_probe = v; this->tmpvar_counter = 0; + this->action_counter = 0; // If we about to emit a probe that is exactly the same as another // probe previously emitted, make the second probe just call the @@ -1555,6 +1543,14 @@ c_unparser::emit_probe (derived_probe* v) v->body->visit (this); + record_actions(0, true); + + 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() << "CATCH_DEREF_FAULT ();"; + } + o->newline(-1) << "out:"; // NB: no need to uninitialize locals, except if arrays/stats can // someday be local @@ -1566,14 +1562,6 @@ 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"; } @@ -2049,18 +2037,22 @@ c_unparser_assignment::c_assignop(tmpvar & res, o->newline() << lval << " = " << rval << ";"; res = rval; } - else - { - if (macop == "/=") - o->newline() << lval << " = _stp_div64 (&c->last_error, " - << lval << ", " << rval << ");"; - else if (macop == "%=") - o->newline() << lval << " = _stp_mod64 (&c->last_error, " - << lval << ", " << rval << ");"; + else + { + if (macop == "/=" || macop == "%=") + { + o->newline() << "if (unlikely(!" << rval << ")) {"; + o->newline(1) << "c->last_error = \"division by 0\";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; + o->newline() << lval << " = " + << ((macop == "/=") ? "_stp_div64" : "_stp_mod64") + << " (NULL, " << lval << ", " << rval << ");"; + } else o->newline() << lval << " " << macop << " " << rval << ";"; res = lval; - } + } } } else @@ -2210,39 +2202,24 @@ c_unparser::getiter(symbol *s) } - -// An artificial common "header" for each statement. This is where -// activity counts limits and error state early exits are enforced. +// Queue up some actions to remove from actionremaining. Set update=true at +// the end of basic blocks to actually update actionremaining and check it +// against MAXACTION. void -c_unparser::visit_statement (statement *s, unsigned actions, bool stmtize) +c_unparser::record_actions (unsigned actions, bool update) { - // For some constructs, it is important to avoid an error branch - // right to the bottom of the probe/function. The foreach() - // iteration construct is one example. Instead, if we are nested - // within a loop, we branch merely to its "break" label. The next - // statement will branch one level higher, and so on, until we can - // go straight "out". - string outlabel = "out"; - unsigned loops = loop_break_labels.size(); - if (loops > 0) - outlabel = loop_break_labels[loops-1]; - - if (s) - { - o->newline() << "if (unlikely (c->last_error)) goto " << outlabel << ";"; - assert (s->tok); - if (stmtize) - o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";"; - } + action_counter += actions; - if (actions > 0) + // Update if needed, or after queueing up a few actions, in case of very + // large code sequences. + if ((update && action_counter > 0) || action_counter >= 10/*<-arbitrary*/) { - o->newline() << "c->actionremaining -= " << actions << ";"; - // XXX: This check is inserted too frequently. + o->newline() << "c->actionremaining -= " << action_counter << ";"; o->newline() << "if (unlikely (c->actionremaining <= 0)) {"; o->newline(1) << "c->last_error = \"MAXACTION exceeded\";"; - o->newline() << "goto " << outlabel << ";"; + o->newline() << "goto out;"; o->newline(-1) << "}"; + action_counter = 0; } } @@ -2253,13 +2230,6 @@ c_unparser::visit_block (block *s) o->newline() << "{"; o->indent (1); - // visit_statement (s, 0, false); - // - // NB: this is not necessary, since the last_error can be handled - // just as easily by the first real body statement, and the - // last_stmt won't be used since this nesting structure cannot - // itself cause an error. - for (unsigned i=0; i<s->statements.size(); i++) { try @@ -2279,12 +2249,6 @@ c_unparser::visit_block (block *s) void c_unparser::visit_embeddedcode (embeddedcode *s) { - // visit_statement (s, 1, true); - // - // NB: this is not necessary, since this can occur only at the top - // level of a function (so no errors can be pending), and the - // action-count is already incremented at the point of call. - o->newline() << "{"; o->newline(1) << s->code; o->newline(-1) << "}"; @@ -2294,12 +2258,6 @@ c_unparser::visit_embeddedcode (embeddedcode *s) void c_unparser::visit_null_statement (null_statement *) { - // visit_statement (s, 0, false); - // - // NB: this is not necessary, since the last_error can be handled just as - // easily by the next statement, and the last_stmt won't be used since this - // statement cannot cause an error. - o->newline() << "/* null */;"; } @@ -2307,17 +2265,17 @@ c_unparser::visit_null_statement (null_statement *) void c_unparser::visit_expr_statement (expr_statement *s) { - visit_statement (s, 1, false); o->newline() << "(void) "; s->value->visit (this); o->line() << ";"; + record_actions(1); } void c_unparser::visit_if_statement (if_statement *s) { - visit_statement (s, 1, false); + record_actions(1, true); o->newline() << "if ("; o->indent (1); s->condition->visit (this); @@ -2325,12 +2283,14 @@ c_unparser::visit_if_statement (if_statement *s) o->line() << ") {"; o->indent (1); s->thenblock->visit (this); + record_actions(0, true); o->newline(-1) << "}"; if (s->elseblock) { o->newline() << "else {"; o->indent (1); s->elseblock->visit (this); + record_actions(0, true); o->newline(-1) << "}"; } } @@ -2380,8 +2340,6 @@ c_tmpcounter::visit_for_loop (for_loop *s) void c_unparser::visit_for_loop (for_loop *s) { - visit_statement (s, 1, false); - string ctr = stringify (label_counter++); string toplabel = "top_" + ctr; string contlabel = "continue_" + ctr; @@ -2389,6 +2347,7 @@ c_unparser::visit_for_loop (for_loop *s) // initialization if (s->init) s->init->visit (this); + record_actions(1, true); // condition o->newline(-1) << toplabel << ":"; @@ -2397,7 +2356,7 @@ c_unparser::visit_for_loop (for_loop *s) // Equivalently, it can stand for the evaluation of the condition // expression. o->indent(1); - visit_statement (0, 1, false); + record_actions(1); o->newline() << "if (! ("; if (s->cond->type != pe_long) @@ -2409,6 +2368,7 @@ c_unparser::visit_for_loop (for_loop *s) loop_break_labels.push_back (breaklabel); loop_continue_labels.push_back (contlabel); s->block->visit (this); + record_actions(0, true); loop_break_labels.pop_back (); loop_continue_labels.pop_back (); @@ -2529,8 +2489,6 @@ c_unparser::visit_foreach_loop (foreach_loop *s) if (array) { - visit_statement (s, 1, false); - mapvar mv = getmap (array->referent, s->tok); itervar iv = getiter (array); vector<var> keys; @@ -2555,9 +2513,10 @@ c_unparser::visit_foreach_loop (foreach_loop *s) // aggregate array if required if (mv.is_parallel()) { - o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << "))"; + o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << ")) {"; o->newline(1) << "c->last_error = \"aggregation overflow in " << mv << "\";"; - o->indent(-1); + o->newline() << "goto out;"; + o->newline(-1) << "}"; // sort array if desired if (s->sort_direction) @@ -2624,6 +2583,8 @@ c_unparser::visit_foreach_loop (foreach_loop *s) o->newline() << *limitv << " = 0LL;"; } + record_actions(1, true); + // condition o->newline(-1) << toplabel << ":"; @@ -2631,7 +2592,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s) // Equivalently, it can stand for the evaluation of the // condition expression. o->indent(1); - visit_statement (0, 1, false); + record_actions(1); o->newline() << "if (! (" << iv << ")) goto " << breaklabel << ";"; @@ -2659,6 +2620,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s) c_assign (v, iv.get_key (v.type(), i), s->tok); } s->block->visit (this); + record_actions(0, true); o->newline(-1) << "}"; loop_break_labels.pop_back (); loop_continue_labels.pop_back (); @@ -2703,6 +2665,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s) } // XXX: break / continue don't work here yet + record_actions(1, true); o->newline() << "for (" << bucketvar << " = 0; " << bucketvar << " < " << v.buckets() << "; " << bucketvar << "++) { "; @@ -2720,6 +2683,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s) } s->block->visit (this); + record_actions(1, true); o->newline(-1) << "}"; } } @@ -2728,8 +2692,6 @@ c_unparser::visit_foreach_loop (foreach_loop *s) void c_unparser::visit_return_statement (return_statement* s) { - visit_statement (s, 1, false); - if (current_function == 0) throw semantic_error ("cannot 'return' from probe", s->tok); @@ -2738,21 +2700,19 @@ c_unparser::visit_return_statement (return_statement* s) "vs", s->tok); c_assign ("l->__retvalue", s->value, "return value"); - o->newline() << "c->last_error = \"\";"; - // NB: last_error needs to get reset to NULL in the caller - // probe/function + record_actions(1, true); + o->newline() << "goto out;"; } void c_unparser::visit_next_statement (next_statement* s) { - visit_statement (s, 1, false); - if (current_probe == 0) throw semantic_error ("cannot 'next' from function", s->tok); - o->newline() << "c->last_error = \"\";"; + record_actions(1, true); + o->newline() << "goto out;"; } @@ -2879,19 +2839,19 @@ c_tmpcounter::visit_delete_statement (delete_statement* s) void c_unparser::visit_delete_statement (delete_statement* s) { - visit_statement (s, 1, false); delete_statement_operand_visitor dv (this); s->value->visit (&dv); + record_actions(1); } void c_unparser::visit_break_statement (break_statement* s) { - visit_statement (s, 1, false); if (loop_break_labels.size() == 0) throw semantic_error ("cannot 'break' outside loop", s->tok); + record_actions(1, true); string label = loop_break_labels[loop_break_labels.size()-1]; o->newline() << "goto " << label << ";"; } @@ -2900,10 +2860,10 @@ c_unparser::visit_break_statement (break_statement* s) void c_unparser::visit_continue_statement (continue_statement* s) { - visit_statement (s, 1, false); if (loop_continue_labels.size() == 0) throw semantic_error ("cannot 'continue' outside loop", s->tok); + record_actions(1, true); string label = loop_continue_labels[loop_continue_labels.size()-1]; o->newline() << "goto " << label << ";"; } @@ -3001,8 +2961,6 @@ c_unparser::visit_binary_expression (binary_expression* e) o->line() << "({"; o->indent(1); - // NB: Need last_stmt set here because of possible last_error generation - o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; if (e->left->tok->type == tok_number) left.override(c_expression(e->left)); @@ -3022,8 +2980,13 @@ c_unparser::visit_binary_expression (binary_expression* e) o->line() << ";"; } + o->newline() << "if (unlikely(!" << right << ")) {"; + o->newline(1) << "c->last_error = \"division by 0\";"; + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64") - << " (&c->last_error, " << left << ", " << right << ");"; + << " (NULL, " << left << ", " << right << ");"; o->newline(-1) << "})"; } @@ -3741,16 +3704,19 @@ c_unparser::visit_arrayindex (arrayindex* e) // PR 2142+2610: empty aggregates o->newline() << "if (unlikely (" << agg.value() << " == NULL)" - << " || " << agg.value() << "->count == 0)"; + << " || " << agg.value() << "->count == 0) {"; o->newline(1) << "c->last_error = \"empty aggregate\";"; - o->newline(-1) << "else {"; + o->newline() << "goto out;"; + o->newline(-1) << "} else {"; o->newline(1) << "if (" << histogram_index_check(*v, idx[0]) << ")"; o->newline(1) << res << " = " << agg << "->histogram[" << idx[0] << "];"; - o->newline(-1) << "else"; + o->newline(-1) << "else {"; o->newline(1) << "c->last_error = \"histogram index out of range\";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; o->newline(-1) << "}"; - o->newline(-1) << res << ";"; + o->newline() << res << ";"; delete v; } @@ -3954,6 +3920,7 @@ c_unparser::visit_functioncall (functioncall* e) // call function o->newline() << "function_" << c_varname (r->name) << " (c);"; + o->newline() << "if (unlikely(c->last_error)) goto out;"; // return result from retvalue slot if (r->type == pe_unknown) @@ -4050,6 +4017,7 @@ c_unparser::visit_print_format (print_format* e) << " || " << agg.value() << "->count == 0) {"; o->newline(1) << "c->last_error = \"empty aggregate\";"; o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; + o->newline() << "goto out;"; o->newline(-1) << "} else"; o->newline(1) << "_stp_stat_print_histogram (" << v->hist() << ", " << agg.value() << ");"; o->indent(-1); @@ -4144,9 +4112,7 @@ c_unparser::visit_print_format (print_format* e) 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); + // Make the [s]printf call... // Generate code to check that any pointer arguments are actually accessible. */ int arg_ix = 0; @@ -4187,7 +4153,6 @@ c_unparser::visit_print_format (print_format* e) o->line() << tmp[0].value() << ");"; else o->line() << '"' << format_string << "\");"; - o->newline(-1) << "}"; return; } if (use_print) @@ -4197,7 +4162,6 @@ c_unparser::visit_print_format (print_format* e) o->line() << tmp[0].value() << ");"; else o->line() << '"' << format_string << "\");"; - o->newline(-1) << "}"; return; } @@ -4232,7 +4196,6 @@ c_unparser::visit_print_format (print_format* e) } o->line() << ");"; - o->newline(-1) << "}"; o->newline() << res.value() << ";"; } } @@ -4307,16 +4270,18 @@ c_unparser::visit_stat_op (stat_op* e) else { o->newline() << "if (unlikely (" << agg.value() << " == NULL)" - << " || " << agg.value() << "->count == 0)"; + << " || " << agg.value() << "->count == 0) {"; o->newline(1) << "c->last_error = \"empty aggregate\";"; - o->indent(-1); + o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; } o->newline() << "else"; o->indent(1); switch (e->ctype) { case sc_average: - c_assign(res, ("_stp_div64(&c->last_error, " + agg.value() + "->sum, " + c_assign(res, ("_stp_div64(NULL, " + agg.value() + "->sum, " + agg.value() + "->count)"), e->tok); break; @@ -4361,36 +4326,50 @@ c_unparser::visit_hist_op (hist_op*) } -static map< Dwarf_Addr, string> addrmap; - -#include <string.h> -static int -kernel_filter (const char *module, const char *file __attribute__((unused))) +struct unwindsym_dump_context { - return !strcmp(module,"kernel"); -} + systemtap_session& session; + ostream& output; +}; + static int -get_symbols (Dwfl_Module *m, - void **userdata __attribute__ ((unused)), - const char *name __attribute__ ((unused)), - Dwarf_Addr base __attribute__ ((unused)), - void *arg __attribute__ ((unused))) +dump_unwindsyms (Dwfl_Module *m, + void **userdata __attribute__ ((unused)), + const char *name, + Dwarf_Addr base, + void *arg) { + unwindsym_dump_context* c = (unwindsym_dump_context*) arg; + assert (c); + + string modname = name; + + // skip modules/files we're not actually interested in + if (c->session.unwindsym_modules.find(modname) == c->session.unwindsym_modules.end()) + return DWARF_CB_OK; + + if (c->session.verbose > 1) + clog << "dump_unwindsyms " << name << " base=0x" << hex << base << dec << endl; + + // We want to extract several bits of information: + // - parts of the program-header that map the file's physical offsets to the text section + // - symbol table of the text section + // - the contents .debug_frame section + // In the future, we'll also care about data symbols. + int syments = dwfl_module_getsymtab(m); assert(syments); for (int i = 1; i < syments; ++i) { GElf_Sym sym; const char *name = dwfl_module_getsym(m, i, &sym, NULL); - if (name) { - if (GELF_ST_TYPE (sym.st_info) == STT_FUNC || - strcmp(name, "_etext") == 0 || - strcmp(name, "_stext") == 0 || - strcmp(name, "modules_op") == 0) - addrmap[sym.st_value] = name; - } + if (name) + { + if (GELF_ST_TYPE (sym.st_info) == STT_FUNC) + ; // addrmap[sym.st_value] = name; + } } return DWARF_CB_OK; } @@ -4399,26 +4378,23 @@ get_symbols (Dwfl_Module *m, void emit_symbol_data (systemtap_session& s) { - ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str()); - s.op->newline() << "\n\n#include \"stap-symbols.h\""; + string symfile = "stap-symbols.h"; + ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str()); - if (s.verbose > 1) - { - std::set<std::string>::iterator it = s.unwindsym_modules.begin(); - clog << "unwindsym modules: "; - while (it != s.unwindsym_modules.end()) - { - clog << *(it++) << " "; - } - clog << endl; - } + unwindsym_dump_context ctx = { s, kallsyms_out }; + + s.op->newline() << "\n\n#include \"" << symfile << "\""; + // XXX: copied from tapsets.cxx, sadly static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build"; static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); static char *debuginfo_path = (debuginfo_env_arr ? - debuginfo_env_arr : debuginfo_path_arr); - + debuginfo_env_arr : debuginfo_path_arr); + static const char *debug_path = (debuginfo_env_arr ? + debuginfo_env_arr : s.kernel_release.c_str()); + + // ---- step 1: process any kernel modules listed static const Dwfl_Callbacks kernel_callbacks = { dwfl_linux_kernel_find_elf, @@ -4431,27 +4407,55 @@ emit_symbol_data (systemtap_session& s) if (!dwfl) throw semantic_error ("cannot open dwfl"); dwfl_report_begin (dwfl); - - int rc = dwfl_linux_kernel_report_offline (dwfl, - s.kernel_release.c_str(), - kernel_filter); + int rc = dwfl_linux_kernel_report_offline (dwfl, debug_path, NULL /* XXX: filtering callback */); dwfl_report_end (dwfl, NULL, NULL); - if (rc < 0) - throw semantic_error ("dwfl rc"); - - dwfl_getmodules (dwfl, &get_symbols, NULL, 0); + dwfl_assert ("dwfl_linux_kernel_report_offline", rc); + ptrdiff_t off = 0; + do + { + if (pending_interrupts) return; + off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); + } + while (off > 0); + dwfl_assert("dwfl_getmodules", off == 0); dwfl_end(dwfl); - - int i = 0; - map< Dwarf_Addr, string>::iterator pos; - kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {"; - for (pos = addrmap.begin(); pos != addrmap.end(); pos++) { - kallsyms_out << " { 0x" << hex << pos->first << ", " << "\"" << pos->second << "\" },\n"; - i++; - } - - kallsyms_out << "};\n"; - kallsyms_out << "unsigned _stp_num_kernel_symbols = " << dec << i << ";\n"; + + + // ---- step 2: process any user modules (files) listed + static const Dwfl_Callbacks user_callbacks = + { + NULL, /* dwfl_linux_kernel_find_elf, */ + dwfl_standard_find_debuginfo, + dwfl_offline_section_address, + & debuginfo_path + }; + + for (std::set<std::string>::iterator it = s.unwindsym_modules.begin(); + it != s.unwindsym_modules.end(); + it++) + { + string modname = *it; + assert (modname.length() != 0); + if (modname[0] != '/') continue; // user-space files must be full paths + + Dwfl *dwfl = dwfl_begin (&user_callbacks); + if (!dwfl) + throw semantic_error ("cannot create dwfl for " + modname); + + dwfl_report_begin (dwfl); + Dwfl_Module* mod = dwfl_report_offline (dwfl, modname.c_str(), modname.c_str(), -1); + dwfl_report_end (dwfl, NULL, NULL); + dwfl_assert ("dwfl_report_offline", mod); + ptrdiff_t off = 0; + do + { + if (pending_interrupts) return; + off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); + } + while (off > 0); + dwfl_assert("dwfl_getmodules", off == 0); + dwfl_end(dwfl); + } } @@ -4532,7 +4536,10 @@ translate_pass (systemtap_session& s) s.op->newline() << "#include <linux/delay.h>"; s.op->newline() << "#include <linux/profile.h>"; s.op->newline() << "#include <linux/random.h>"; + s.op->newline() << "#include <linux/utsrelease.h>"; s.op->newline() << "#include <linux/utsname.h>"; + s.op->newline() << "#include <linux/version.h>"; + s.op->newline() << "#include <linux/compile.h>"; s.op->newline() << "#include \"loc2c-runtime.h\" "; // XXX: old 2.6 kernel hack |